timescaledb-rails 0.1.3 → 0.1.5

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: 2b682514201eb2e88a829297e9582cfe9513a127432de8acf7a060b769f38ca2
4
- data.tar.gz: c30e268a3b9be19d95537230126a1c12c8aa97746afb3227f0e544293527d399
3
+ metadata.gz: 7fc0e42b6db3e42267d014923180abf3c64a643937942b8b3f17ad9b2a3bf223
4
+ data.tar.gz: 96c3105df56f184894cdd7e3ca8658b083a87e8a050711c17e52eeae6c836c3e
5
5
  SHA512:
6
- metadata.gz: 1011081beb9b4a23ff4ceafe7b47278ad7418ace4438e3a67097e8db933802afd15875ba0a28f4141154ba12170bff7e4db28c4d8c5040d716c49f53b6c8d328
7
- data.tar.gz: cd429d48862ce9dd82002fe35d3953814e893bd066a6e2143a9d5245036015d21b2b23174165389888225649e963a696a2328e0b5a228bf88efc268c39a5919e
6
+ metadata.gz: 9988f806f0512c73456e531dd42dfe3f3c5765d9ee426bcf6f4b45e3098568fcac3518884abde8fb473a42cba66d73aa4558631b2806256ea4726496a212bdb9
7
+ data.tar.gz: e85fa03def618ed5d114275a6f2b929871ca0c0ea52e95ada85cca332baa2f1252f8a6bc3fc29be544aaa8dc8225dbcda52df83903bedd530a63b3683be30e8b
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
- # TimescaleDB extension for Rails [![Actions Status](https://github.com/crunchloop/timescaledb-rails/workflows/CI/badge.svg?branch=main)](https://github.com/crunchloop/timescaledb-rails/actions?query=workflow%3ACI)
2
-
3
- `timescaledb-rails` extends ActiveRecord PostgreSQL adapter and provides features from [`TimescaleDB`](https://www.timescale.com). It provides support for hypertables and other features added by TimescaleDB PostgreSQL extension.
1
+ # TimescaleDB extension for Rails [![Gem Version](https://badge.fury.io/rb/timescaledb-rails.svg)](https://badge.fury.io/rb/timescaledb-rails) [![Actions Status](https://github.com/crunchloop/timescaledb-rails/workflows/CI/badge.svg?branch=main)](https://github.com/crunchloop/timescaledb-rails/actions?query=workflow%3ACI)
4
2
 
3
+ `timescaledb-rails` extends ActiveRecord PostgreSQL adapter and provides features from [TimescaleDB](https://www.timescale.com). It provides support for hypertables and other features added by TimescaleDB PostgreSQL extension.
5
4
 
6
5
  ## Installation
7
6
 
@@ -17,16 +16,18 @@ Or include it in your project's `Gemfile` with Bundler:
17
16
  gem 'timescaledb-rails', '~> 0.1'
18
17
  ```
19
18
 
20
- ## Examples
19
+ ## Usage
20
+
21
+ ### Migrations
21
22
 
22
- Create a hypertable from a PostgreSQL table by doing:
23
+ Create a hypertable from a PostgreSQL table
23
24
 
24
25
  ```ruby
25
26
  class CreateEvent < ActiveRecord::Migration[7.0]
26
27
  def change
27
28
  create_table :events, id: false do |t|
28
29
  t.string :name, null: false
29
- t.time :occured_at, null: false
30
+ t.time :occurred_at, null: false
30
31
 
31
32
  t.timestamps
32
33
  end
@@ -36,7 +37,7 @@ class CreateEvent < ActiveRecord::Migration[7.0]
36
37
  end
37
38
  ```
38
39
 
39
- Create a hypertable without a PostgreSQL table by doing:
40
+ Create a hypertable without a PostgreSQL table
40
41
 
41
42
  ```ruby
42
43
  class CreatePayloadHypertable < ActiveRecord::Migration[7.0]
@@ -50,29 +51,228 @@ class CreatePayloadHypertable < ActiveRecord::Migration[7.0]
50
51
  end
51
52
  ```
52
53
 
53
- Enable hypertable compression by doing:
54
+ Add hypertable compression
54
55
 
55
56
  ```ruby
56
57
  class AddEventCompression < ActiveRecord::Migration[7.0]
57
- def change
58
- add_hypertable_compression :events, 20.days, segment_by: :name, order_by: 'occured_at DESC'
58
+ def up
59
+ add_hypertable_compression :events, 20.days, segment_by: :name, order_by: 'occurred_at DESC'
60
+ end
61
+
62
+ def down
63
+ remove_hypertable_compression :events
59
64
  end
60
65
  end
61
66
  ```
62
67
 
63
- Disable hypertable compression by doing:
68
+ Add hypertable retention policy
64
69
 
65
70
  ```ruby
66
- class RemoveEventCompression < ActiveRecord::Migration[7.0]
67
- def change
68
- remove_hypertable_compression :events
71
+ class AddEventRetentionPolicy < ActiveRecord::Migration[7.0]
72
+ def up
73
+ add_hypertable_retention_policy :events, 1.year
74
+ end
75
+
76
+ def down
77
+ remove_hypertable_retention_policy :events
78
+ end
79
+ end
80
+ ```
81
+
82
+ Add hypertable reorder policy
83
+
84
+ ```ruby
85
+ class AddEventReorderPolicy < ActiveRecord::Migration[7.0]
86
+ def up
87
+ add_hypertable_reorder_policy :events, :index_events_on_created_at_and_name
88
+ end
89
+
90
+ def down
91
+ remove_hypertable_reorder_policy :events
69
92
  end
70
93
  end
71
94
  ```
72
95
 
96
+ Create continuous aggregate
97
+
98
+ ```ruby
99
+ class CreateTemperatureEventAggregate < ActiveRecord::Migration[7.0]
100
+ def up
101
+ create_continuous_aggregate(
102
+ :temperature_events,
103
+ Event.time_bucket(1.day).avg(:value).temperature.to_sql
104
+ )
105
+
106
+ add_continuous_aggregate_policy(:temperature_events, 1.month, 1.day, 1.hour)
107
+ end
108
+
109
+ def down
110
+ drop_continuous_aggregate(:temperature_events)
111
+
112
+ remove_continuous_aggregate_policy(:temperature_events)
113
+ end
114
+ end
115
+ ```
116
+
117
+ > **Reversible Migrations:**
118
+ >
119
+ > Above examples implement `up`/`down` methods to better document all the different APIs. Feel free to use `change` method, timescaledb-rails defines all the reverse calls for each API method so Active Record can automatically figure out how to reverse your migration.
120
+
121
+ ### Models
122
+
123
+ If one of your models need TimescaleDB support, just include `Timescaledb::Rails::Model`
124
+
125
+ ```ruby
126
+ class Payload < ActiveRecord::Base
127
+ include Timescaledb::Rails::Model
128
+
129
+ self.primary_key = 'id'
130
+ end
131
+ ```
132
+
133
+ When hypertable belongs to a non default schema, don't forget to override `table_name`
134
+
135
+ ```ruby
136
+ class Event < ActiveRecord::Base
137
+ include Timescaledb::Rails::Model
138
+
139
+ self.table_name = 'tdb.events'
140
+ end
141
+ ```
142
+
143
+ Using `.find` is not recommended, to achieve more performat results, use these other find methods
144
+
145
+ ```ruby
146
+ # When you know the exact time value
147
+ Payload.find_at_time(111, Time.new(2022, 01, 01, 10, 15, 30))
148
+
149
+ # If you know that the record occurred after a given time
150
+ Payload.find_after(222, 11.days.ago)
151
+
152
+ # Lastly, if you want to scope the search by a time range
153
+ Payload.find_between(333, 1.week.ago, 1.day.ago)
154
+ ```
155
+
156
+ If you need to query data for a specific time period, `Timescaledb::Rails::Model` includes useful scopes
157
+
158
+ ```ruby
159
+ # If you want to get all records from last year
160
+ Event.last_year #=> [#<Event name...>, ...]
161
+
162
+ # Or if you want to get records from this year
163
+ Event.this_year #=> [#<Event name...>, ...]
164
+
165
+ # Or even getting records from today
166
+ Event.today #=> [#<Event name...>, ...]
167
+ ```
168
+
169
+ Here the list of all available scopes
170
+
171
+ * last_year
172
+ * last_month
173
+ * last_week
174
+ * this_year
175
+ * this_month
176
+ * this_week
177
+ * yesterday
178
+ * today
179
+
180
+ If you still need to query data by other time periods, take a look at these other scopes
181
+
182
+ ```ruby
183
+ # If you want to get all records that occurred in the last 30 minutes
184
+ Event.after(30.minutes.ago) #=> [#<Event name...>, ...]
185
+
186
+ # If you want to get records that occurred in the last 4 days, excluding today
187
+ Event.between(4.days.ago, 1.day.ago) #=> [#<Event name...>, ...]
188
+
189
+ # If you want to get records that occurred at a specific time
190
+ Event.at_time(Time.new(2023, 01, 04, 10, 20, 30)) #=> [#<Event name...>, ...]
191
+ ```
192
+
193
+ If you need information about your hypertable, use the following helper methods to get useful information
194
+
195
+ ```ruby
196
+ # Hypertable metadata
197
+ Event.hypertable #=> #<Timescaledb::Rails::Hypertable ...>
198
+
199
+ # Hypertable chunks metadata
200
+ Event.hypertable_chunks #=> [#<Timescaledb::Rails::Chunk ...>, ...]
201
+
202
+ # Hypertable jobs, it includes jobs like compression, retention or reorder policies, etc.
203
+ Event.hypertable_jobs #=> [#<Timescaledb::Rails::Job ...>, ...]
204
+
205
+ # Hypertable dimensions, like time or space dimensions
206
+ Event.hypertable_dimensions #=> [#<Timescaledb::Rails::Dimension ...>, ...]
207
+
208
+ # Hypertable compression settings
209
+ Event.hypertable_compression_settings #=> [#<Timescaledb::Rails::CompressionSetting ...>, ...]
210
+ ```
211
+
212
+ If you need to compress or decompress a specific chunk
213
+
214
+ ```ruby
215
+ chunk = Event.hypertable_chunks.first
216
+
217
+ chunk.compress! unless chunk.is_compressed?
218
+
219
+ chunk.decompress! if chunk.is_compressed?
220
+ ```
221
+
222
+ If you need to reorder a specific chunk
223
+
224
+ ```ruby
225
+ chunk = Event.hypertable_chunks.first
226
+
227
+ # If an index is not specified, it will use the one from the reorder policy
228
+ # In case there is no reorder policy index it will raise an ArgumentError
229
+ chunk.reorder!
230
+
231
+ # If an index is specified it will use that index
232
+ chunk.reorder!(index)
233
+ ```
234
+
235
+ If you need to manually refresh a continuous aggregate
236
+
237
+ ```ruby
238
+ aggregate = Event.hypertable.continuous_aggregates.first
239
+
240
+ aggregate.refresh!(5.days.ago, 1.day.ago)
241
+ ```
242
+
243
+ ### Hyperfunctions
244
+
245
+ #### Time bucket
246
+
247
+ You can call the time bucket function with an interval (note that leaving the target column blank will use the default time column of the hypertable)
248
+
249
+ ```ruby
250
+ Event.time_bucket(1.day)
251
+
252
+ Event.time_bucket('1 day')
253
+
254
+ Event.time_bucket(1.day, :created_at)
255
+
256
+ Event.time_bucket(1.day, 'occurred_at')
257
+ ```
258
+
259
+ You may add aggregation like so:
260
+
261
+ ```ruby
262
+ Event.time_bucket(1.day).avg(:column)
263
+ Event.time_bucket(1.day).sum(:column)
264
+ Event.time_bucket(1.day).min(:column)
265
+ Event.time_bucket(1.day).max(:column)
266
+ Event.time_bucket(1.day).count
267
+ ```
268
+
269
+ ## Contributing
270
+
271
+ Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests.
272
+
73
273
  ## Supported Ruby/Rails versions
74
274
 
75
- Supported Ruby/Rails versions are listed in [`.github/workflows/ci.yaml`](https://github.com/crunchloop/timescaledb-rails/blob/main/.github/workflows/ci.yaml)
275
+ Supported Ruby/Rails versions are listed in [`.github/workflows/ci.yaml`](./.github/workflows/ci.yaml)
76
276
 
77
277
  ## License
78
278
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Timescaledb
4
+ module Rails
5
+ module ActiveRecord
6
+ # :nodoc:
7
+ module Base
8
+ extend ActiveSupport::Concern
9
+
10
+ # :nodoc:
11
+ module ClassMethods
12
+ # Returns if the current active record model is a hypertable.
13
+ def hypertable?
14
+ connection.hypertable_exists?(table_name)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -17,6 +17,38 @@ module Timescaledb
17
17
  record(:remove_hypertable_compression, args, &block)
18
18
  end
19
19
 
20
+ def add_hypertable_reorder_policy(*args, &block)
21
+ record(:add_hypertable_reorder_policy, args, &block)
22
+ end
23
+
24
+ def remove_hypertable_reorder_policy(*args, &block)
25
+ record(:remove_hypertable_reorder_policy, args, &block)
26
+ end
27
+
28
+ def add_hypertable_retention_policy(*args, &block)
29
+ record(:add_hypertable_retention_policy, args, &block)
30
+ end
31
+
32
+ def remove_hypertable_retention_policy(*args, &block)
33
+ record(:remove_hypertable_retention_policy, args, &block)
34
+ end
35
+
36
+ def create_continuous_aggregate(*args, &block)
37
+ record(:create_continuous_aggregate, args, &block)
38
+ end
39
+
40
+ def drop_continuous_aggregate(*args, &block)
41
+ record(:drop_continuous_aggregate, args, &block)
42
+ end
43
+
44
+ def add_continuous_aggregate_policy(*args, &block)
45
+ record(:add_continuous_aggregate_policy, args, &block)
46
+ end
47
+
48
+ def remove_continuous_aggregate_policy(*args, &block)
49
+ record(:remove_continuous_aggregate_policy, args, &block)
50
+ end
51
+
20
52
  def invert_create_hypertable(args, &block)
21
53
  if block.nil?
22
54
  raise ::ActiveRecord::IrreversibleMigration, 'create_hypertable is only reversible if given a block (can be empty).' # rubocop:disable Layout/LineLength
@@ -36,6 +68,54 @@ module Timescaledb
36
68
 
37
69
  [:add_hypertable_compression, args, block]
38
70
  end
71
+
72
+ def invert_add_hypertable_retention_policy(args, &block)
73
+ [:remove_hypertable_retention_policy, args, block]
74
+ end
75
+
76
+ def invert_remove_hypertable_retention_policy(args, &block)
77
+ if args.size < 2
78
+ raise ::ActiveRecord::IrreversibleMigration, 'remove_hypertable_retention_policy is only reversible if given table name and drop after period.' # rubocop:disable Layout/LineLength
79
+ end
80
+
81
+ [:add_hypertable_retention_policy, args, block]
82
+ end
83
+
84
+ def invert_add_hypertable_reorder_policy(args, &block)
85
+ [:remove_hypertable_reorder_policy, args, block]
86
+ end
87
+
88
+ def invert_remove_hypertable_reorder_policy(args, &block)
89
+ if args.size < 2
90
+ raise ::ActiveRecord::IrreversibleMigration, 'remove_hypertable_reorder_policy is only reversible if given table name and index name.' # rubocop:disable Layout/LineLength
91
+ end
92
+
93
+ [:add_hypertable_reorder_policy, args, block]
94
+ end
95
+
96
+ def invert_create_continuous_aggregate(args, &block)
97
+ [:drop_continuous_aggregate, args, block]
98
+ end
99
+
100
+ def invert_drop_continuous_aggregate(args, &block)
101
+ if args.size < 2
102
+ raise ::ActiveRecord::IrreversibleMigration, 'drop_continuous_aggregate is only reversible if given view name and view query.' # rubocop:disable Layout/LineLength
103
+ end
104
+
105
+ [:create_continuous_aggregate, args, block]
106
+ end
107
+
108
+ def invert_add_continuous_aggregate_policy(args, &block)
109
+ [:remove_continuous_aggregate_policy, args, block]
110
+ end
111
+
112
+ def invert_remove_continuous_aggregate_policy(args, &block)
113
+ if args.size < 4
114
+ raise ::ActiveRecord::IrreversibleMigration, 'remove_continuous_aggregate_policy is only reversible if given view name, start offset, end offset and schedule interval.' # rubocop:disable Layout/LineLength
115
+ end
116
+
117
+ [:add_continuous_aggregate_policy, args, block]
118
+ end
39
119
  end
40
120
  end
41
121
  end
@@ -7,36 +7,53 @@ module Timescaledb
7
7
  module Rails
8
8
  module ActiveRecord
9
9
  # :nodoc:
10
+ # rubocop:disable Layout/LineLength
10
11
  module PostgreSQLDatabaseTasks
11
12
  # @override
12
- def structure_dump(filename, extra_flags) # rubocop:disable Metrics/MethodLength
13
+ def structure_dump(filename, extra_flags)
13
14
  extra_flags = Array(extra_flags)
14
- extra_flags << timescale_structure_dump_default_flags if timescale_enabled?
15
+ extra_flags |= timescale_structure_dump_default_flags if timescale_enabled?
15
16
 
16
17
  super(filename, extra_flags)
17
18
 
18
19
  return unless timescale_enabled?
19
20
 
21
+ hypertables(filename)
22
+ continuous_aggregates(filename)
23
+ end
24
+
25
+ def hypertables(filename)
20
26
  File.open(filename, 'a') do |file|
21
27
  Timescaledb::Rails::Hypertable.all.each do |hypertable|
22
28
  drop_ts_insert_trigger_statment(hypertable, file)
23
29
  create_hypertable_statement(hypertable, file)
24
30
  add_hypertable_compression_statement(hypertable, file)
31
+ add_hypertable_reorder_policy_statement(hypertable, file)
32
+ add_hypertable_retention_policy_statement(hypertable, file)
33
+ end
34
+ end
35
+ end
36
+
37
+ def continuous_aggregates(filename)
38
+ File.open(filename, 'a') do |file|
39
+ Timescaledb::Rails::ContinuousAggregate.all.each do |continuous_aggregate|
40
+ create_continuous_aggregate_statement(continuous_aggregate, file)
41
+ add_continuous_aggregate_policy_statement(continuous_aggregate, file)
25
42
  end
26
43
  end
27
44
  end
28
45
 
29
46
  def drop_ts_insert_trigger_statment(hypertable, file)
30
47
  file << "---\n"
31
- file << "--- Drop ts_insert_blocker previously created by pg_dump to avoid pg errors, create_hypertable will re-create it again.\n" # rubocop:disable Layout/LineLength
48
+ file << "--- Drop ts_insert_blocker previously created by pg_dump to avoid pg errors, create_hypertable will re-create it again.\n"
32
49
  file << "---\n\n"
33
- file << "DROP TRIGGER IF EXISTS ts_insert_blocker ON #{hypertable.hypertable_name};\n"
50
+ file << "DROP TRIGGER IF EXISTS ts_insert_blocker ON #{hypertable.hypertable_schema}.#{hypertable.hypertable_name};\n"
34
51
  end
35
52
 
36
53
  def create_hypertable_statement(hypertable, file)
37
54
  options = hypertable_options(hypertable)
38
55
 
39
- file << "SELECT create_hypertable('#{hypertable.hypertable_name}', '#{hypertable.time_column_name}', #{options});\n\n" # rubocop:disable Layout/LineLength
56
+ file << "SELECT create_hypertable('#{hypertable.hypertable_schema}.#{hypertable.hypertable_name}', '#{hypertable.time_column_name}', #{options});\n\n"
40
57
  end
41
58
 
42
59
  def add_hypertable_compression_statement(hypertable, file)
@@ -44,8 +61,35 @@ module Timescaledb
44
61
 
45
62
  options = hypertable_compression_options(hypertable)
46
63
 
47
- file << "ALTER TABLE #{hypertable.hypertable_name} SET (#{options});\n\n"
48
- file << "SELECT add_compression_policy('#{hypertable.hypertable_name}', INTERVAL '#{hypertable.compression_policy_interval}');\n\n" # rubocop:disable Layout/LineLength
64
+ file << "ALTER TABLE #{hypertable.hypertable_schema}.#{hypertable.hypertable_name} SET (#{options});\n\n"
65
+ file << "SELECT add_compression_policy('#{hypertable.hypertable_schema}.#{hypertable.hypertable_name}', INTERVAL '#{hypertable.compression_policy_interval}');\n\n"
66
+ end
67
+
68
+ def add_hypertable_reorder_policy_statement(hypertable, file)
69
+ return unless hypertable.reorder?
70
+
71
+ file << "SELECT add_reorder_policy('#{hypertable.hypertable_schema}.#{hypertable.hypertable_name}', '#{hypertable.reorder_policy_index_name}');\n\n"
72
+ end
73
+
74
+ def add_hypertable_retention_policy_statement(hypertable, file)
75
+ return unless hypertable.retention?
76
+
77
+ file << "SELECT add_retention_policy('#{hypertable.hypertable_schema}.#{hypertable.hypertable_name}', INTERVAL '#{hypertable.retention_policy_interval}');\n\n"
78
+ end
79
+
80
+ def create_continuous_aggregate_statement(continuous_aggregate, file)
81
+ file << "CREATE MATERIALIZED VIEW #{continuous_aggregate.view_schema}.#{continuous_aggregate.view_name} WITH (timescaledb.continuous) AS\n"
82
+ file << "#{continuous_aggregate.view_definition.strip.indent(2)}\n\n"
83
+ end
84
+
85
+ def add_continuous_aggregate_policy_statement(continuous_aggregate, file)
86
+ return unless continuous_aggregate.refresh?
87
+
88
+ start_offset = continuous_aggregate.refresh_start_offset
89
+ end_offset = continuous_aggregate.refresh_end_offset
90
+ schedule_interval = continuous_aggregate.refresh_schedule_interval
91
+
92
+ file << "SELECT add_continuous_aggregate_policy('#{continuous_aggregate.view_schema}.#{continuous_aggregate.view_name}', start_offset => INTERVAL '#{start_offset}', end_offset => INTERVAL '#{end_offset}', schedule_interval => INTERVAL '#{schedule_interval}');\n\n"
49
93
  end
50
94
 
51
95
  def hypertable_options(hypertable)
@@ -56,27 +100,41 @@ module Timescaledb
56
100
  end
57
101
 
58
102
  def hypertable_compression_options(hypertable)
59
- segmentby_setting = hypertable.compression_settings.segmentby_setting.first
60
- orderby_setting = hypertable.compression_settings.orderby_setting.first
61
-
62
103
  sql_statements = ['timescaledb.compress']
63
- sql_statements << "timescaledb.compress_segmentby = '#{segmentby_setting.attname}'" if segmentby_setting
64
104
 
65
- if orderby_setting
66
- orderby = Timescaledb::Rails::OrderbyCompression.new(orderby_setting.attname,
67
- orderby_setting.orderby_asc).to_s
105
+ if (segments = compression_segment_settings(hypertable)).present?
106
+ sql_statements << "timescaledb.compress_segmentby = '#{segments.join(', ')}'"
107
+ end
68
108
 
69
- sql_statements << "timescaledb.compress_orderby = '#{orderby}'"
109
+ if (orders = compression_order_settings(hypertable)).present?
110
+ sql_statements << "timescaledb.compress_orderby = '#{orders.join(', ')}'"
70
111
  end
71
112
 
72
113
  sql_statements.join(', ')
73
114
  end
74
115
 
75
- # Returns `pg_dump` flag to exclude `_timescaledb_internal` schema tables.
116
+ def compression_order_settings(hypertable)
117
+ hypertable.compression_order_settings.map do |os|
118
+ Timescaledb::Rails::OrderbyCompression.new(os.attname, os.orderby_asc).to_s
119
+ end
120
+ end
121
+
122
+ def compression_segment_settings(hypertable)
123
+ hypertable.compression_segment_settings.map(&:attname)
124
+ end
125
+
126
+ # Returns `pg_dump` flags to exclude `_timescaledb_internal` schema tables and
127
+ # exclude the corresponding continuous aggregate views.
76
128
  #
77
- # @return [String]
129
+ # @return [Array<String>]
78
130
  def timescale_structure_dump_default_flags
79
- '--exclude-schema=_timescaledb_internal'
131
+ flags = ['--exclude-schema=_timescaledb_internal']
132
+
133
+ Timescaledb::Rails::ContinuousAggregate.pluck(:view_schema, :view_name).each do |view_schema, view_name|
134
+ flags << "--exclude-table=#{view_schema}.#{view_name}"
135
+ end
136
+
137
+ flags
80
138
  end
81
139
 
82
140
  # @return [Boolean]
@@ -84,6 +142,7 @@ module Timescaledb
84
142
  Timescaledb::Rails::Hypertable.table_exists?
85
143
  end
86
144
  end
145
+ # rubocop:enable Layout/LineLength
87
146
  end
88
147
  end
89
148
  end
@@ -7,7 +7,46 @@ module Timescaledb
7
7
  module Rails
8
8
  module ActiveRecord
9
9
  # :nodoc:
10
- module SchemaDumper
10
+ module SchemaDumper # rubocop:disable Metrics/ModuleLength
11
+ # @override
12
+ def tables(stream)
13
+ super
14
+
15
+ continuous_aggregates(stream)
16
+ stream
17
+ end
18
+
19
+ def continuous_aggregates(stream)
20
+ return unless timescale_enabled?
21
+
22
+ Timescaledb::Rails::ContinuousAggregate.all.each do |continuous_aggregate|
23
+ continuous_aggregate(continuous_aggregate, stream)
24
+ continuous_aggregate_policy(continuous_aggregate, stream)
25
+ end
26
+ end
27
+
28
+ def continuous_aggregate(continuous_aggregate, stream)
29
+ stream.puts " create_continuous_aggregate #{continuous_aggregate.view_name.inspect}, <<-SQL"
30
+ stream.puts " #{continuous_aggregate.view_definition.strip.indent(2)}"
31
+ stream.puts ' SQL'
32
+ stream.puts
33
+ end
34
+
35
+ def continuous_aggregate_policy(continuous_aggregate, stream)
36
+ return unless continuous_aggregate.refresh?
37
+
38
+ options = [
39
+ continuous_aggregate.view_name.inspect,
40
+ continuous_aggregate.refresh_start_offset.inspect,
41
+ continuous_aggregate.refresh_end_offset.inspect,
42
+ continuous_aggregate.refresh_schedule_interval.inspect
43
+ ]
44
+
45
+ stream.puts " add_continuous_aggregate_policy #{options.join(', ')}"
46
+ stream.puts
47
+ end
48
+
49
+ # @override
11
50
  def table(table, stream)
12
51
  super(table, stream)
13
52
 
@@ -16,6 +55,8 @@ module Timescaledb
16
55
 
17
56
  hypertable(hypertable, stream)
18
57
  hypertable_compression(hypertable, stream)
58
+ hypertable_reorder(hypertable, stream)
59
+ hypertable_retention(hypertable, stream)
19
60
  end
20
61
 
21
62
  private
@@ -38,6 +79,24 @@ module Timescaledb
38
79
  stream.puts
39
80
  end
40
81
 
82
+ def hypertable_reorder(hypertable, stream)
83
+ return unless hypertable.reorder?
84
+
85
+ options = [hypertable.hypertable_name.inspect, hypertable.reorder_policy_index_name.inspect]
86
+
87
+ stream.puts " add_hypertable_reorder_policy #{options.join(', ')}"
88
+ stream.puts
89
+ end
90
+
91
+ def hypertable_retention(hypertable, stream)
92
+ return unless hypertable.retention?
93
+
94
+ options = [hypertable.hypertable_name.inspect, hypertable.retention_policy_interval.inspect]
95
+
96
+ stream.puts " add_hypertable_retention_policy #{options.join(', ')}"
97
+ stream.puts
98
+ end
99
+
41
100
  def hypertable_options(hypertable)
42
101
  options = {
43
102
  chunk_time_interval: hypertable.chunk_time_interval
@@ -50,21 +109,27 @@ module Timescaledb
50
109
  end
51
110
 
52
111
  def hypertable_compression_options(hypertable)
53
- segmentby_setting = hypertable.compression_settings.segmentby_setting.first
54
- orderby_setting = hypertable.compression_settings.orderby_setting.first
55
-
56
112
  [].tap do |result|
57
- result << "segment_by: #{segmentby_setting.attname.inspect}" if segmentby_setting
58
-
59
- if orderby_setting
60
- orderby = Timescaledb::Rails::OrderbyCompression.new(orderby_setting.attname,
61
- orderby_setting.orderby_asc).to_s
113
+ if (segments = compression_segment_settings(hypertable)).present?
114
+ result << "segment_by: #{segments.join(', ').inspect}"
115
+ end
62
116
 
63
- result << "order_by: #{orderby.inspect}"
117
+ if (orders = compression_order_settings(hypertable)).present?
118
+ result << "order_by: #{orders.join(', ').inspect}"
64
119
  end
65
120
  end
66
121
  end
67
122
 
123
+ def compression_order_settings(hypertable)
124
+ hypertable.compression_order_settings.map do |os|
125
+ Timescaledb::Rails::OrderbyCompression.new(os.attname, os.orderby_asc).to_s
126
+ end
127
+ end
128
+
129
+ def compression_segment_settings(hypertable)
130
+ hypertable.compression_segment_settings.map(&:attname)
131
+ end
132
+
68
133
  def format_hypertable_option_value(value)
69
134
  case value
70
135
  when String then value.inspect