timescaledb 0.2.4 → 0.2.6
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 +4 -4
- data/.github/workflows/ci.yml +72 -0
- data/.travis.yml +2 -2
- data/Gemfile.lock +2 -2
- data/Gemfile.scenic.lock +2 -4
- data/lib/timescaledb/application_record.rb +7 -0
- data/lib/timescaledb/chunk.rb +1 -1
- data/lib/timescaledb/compression_settings.rb +1 -1
- data/lib/timescaledb/continuous_aggregates.rb +1 -1
- data/lib/timescaledb/dimensions.rb +1 -1
- data/lib/timescaledb/hypertable.rb +1 -1
- data/lib/timescaledb/job.rb +1 -1
- data/lib/timescaledb/job_stats.rb +1 -1
- data/lib/timescaledb/migration_helpers.rb +27 -8
- data/lib/timescaledb/scenic/extension.rb +1 -1
- data/lib/timescaledb/schema_dumper.rb +63 -21
- data/lib/timescaledb/version.rb +1 -1
- data/lib/timescaledb.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06f324ce8793264ad6acb6a0f0f8f107511be08ecf2952e2fab285aeac366d35
|
4
|
+
data.tar.gz: d95da2805b53dafd174bb83fce7cf29cc2f13b5e8543bfa144d424e679aba701
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14ce31badc6ae1eae1f51161a806354fcaea6b2d39197498766b4cefa2022565410f7fc745adfbaf0d51b68d67454460f3aabab2a94444dd377a93193d0465b2
|
7
|
+
data.tar.gz: 573dd6b5ae3bcfa0948176a86561c080a860d72634e1800b750554a694e17a17890a31492e2702b38ced8444b5725586bfcca6cb23109c968748edeb509bcf12
|
@@ -0,0 +1,72 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
pull_request:
|
6
|
+
workflow_dispatch:
|
7
|
+
# schedule:
|
8
|
+
# - cron: '42 5 * * *'
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
test-in-container:
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
ruby: [ '3.1.2' ]
|
16
|
+
database:
|
17
|
+
- 'pg14.6-ts2.9.0-patroni-static-primary-latest'
|
18
|
+
- 'pg13.9-ts2.9-latest'
|
19
|
+
|
20
|
+
services:
|
21
|
+
database:
|
22
|
+
image: timescale/timescaledb-ha:${{matrix.database}}
|
23
|
+
env:
|
24
|
+
POSTGRES_USER: username
|
25
|
+
POSTGRES_PASSWORD: secret
|
26
|
+
POSTGRES_DB: testdb
|
27
|
+
options: >-
|
28
|
+
--health-cmd pg_isready
|
29
|
+
--health-interval 10s
|
30
|
+
--health-timeout 5s
|
31
|
+
--health-retries 5
|
32
|
+
|
33
|
+
|
34
|
+
runs-on: ubuntu-latest
|
35
|
+
name: OS Ruby ${{matrix.ruby}} database ${{matrix.database}}
|
36
|
+
container: ruby:${{matrix.ruby}}
|
37
|
+
|
38
|
+
steps:
|
39
|
+
- uses: actions/checkout@v3
|
40
|
+
|
41
|
+
- name: Show Ruby Version
|
42
|
+
run: |
|
43
|
+
ruby -v
|
44
|
+
|
45
|
+
- name: Install psql
|
46
|
+
run: |
|
47
|
+
apt-get update
|
48
|
+
apt-get install -y postgresql-client
|
49
|
+
|
50
|
+
- name: Show PostgreSQL version and time
|
51
|
+
env:
|
52
|
+
PGPASSWORD: secret
|
53
|
+
run: |
|
54
|
+
echo "SELECT version()" | psql -h database -U username testdb
|
55
|
+
echo "SELECT CURRENT_TIME" | psql -h database -U username testdb
|
56
|
+
|
57
|
+
- name: Setup
|
58
|
+
run: |
|
59
|
+
./bin/setup
|
60
|
+
|
61
|
+
- name: run tsdb
|
62
|
+
run: ./bin/tsdb postgres://username:secret@database:5432/testdb --stats
|
63
|
+
|
64
|
+
- name: Test setup
|
65
|
+
run: |
|
66
|
+
echo PG_URI_TEST="postgres://username:secret@database:5432/testdb" > .env
|
67
|
+
cat .env
|
68
|
+
bundle exec rake test:setup
|
69
|
+
|
70
|
+
- name: Test
|
71
|
+
run: bundle exec rake
|
72
|
+
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
timescaledb (0.2.
|
4
|
+
timescaledb (0.2.6)
|
5
5
|
activerecord
|
6
6
|
activesupport
|
7
7
|
pg (~> 1.2)
|
@@ -33,7 +33,7 @@ GEM
|
|
33
33
|
concurrent-ruby (~> 1.0)
|
34
34
|
method_source (1.0.0)
|
35
35
|
minitest (5.14.4)
|
36
|
-
pg (1.4.
|
36
|
+
pg (1.4.5)
|
37
37
|
pry (0.14.1)
|
38
38
|
coderay (~> 1.1)
|
39
39
|
method_source (~> 1.0)
|
data/Gemfile.scenic.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
timescaledb (0.2.
|
4
|
+
timescaledb (0.2.6)
|
5
5
|
activerecord
|
6
6
|
activesupport
|
7
7
|
pg (~> 1.2)
|
@@ -56,9 +56,7 @@ GEM
|
|
56
56
|
nokogiri (1.12.5)
|
57
57
|
mini_portile2 (~> 2.6.1)
|
58
58
|
racc (~> 1.4)
|
59
|
-
|
60
|
-
racc (~> 1.4)
|
61
|
-
pg (1.4.4)
|
59
|
+
pg (1.4.5)
|
62
60
|
pry (0.14.1)
|
63
61
|
coderay (~> 1.1)
|
64
62
|
method_source (~> 1.0)
|
data/lib/timescaledb/chunk.rb
CHANGED
data/lib/timescaledb/job.rb
CHANGED
@@ -4,7 +4,12 @@ require 'active_record/connection_adapters/postgresql_adapter'
|
|
4
4
|
module Timescaledb
|
5
5
|
# Migration helpers can help you to setup hypertables by default.
|
6
6
|
module MigrationHelpers
|
7
|
-
# create_table
|
7
|
+
# `create_table` accepts a `hypertable` argument with options for creating
|
8
|
+
# a TimescaleDB hypertable.
|
9
|
+
#
|
10
|
+
# See https://docs.timescale.com/api/latest/hypertable/create_hypertable/#optional-arguments
|
11
|
+
# for additional options supported by the plugin.
|
12
|
+
#
|
8
13
|
# @example
|
9
14
|
# options = {
|
10
15
|
# time_column: 'created_at',
|
@@ -27,15 +32,29 @@ module Timescaledb
|
|
27
32
|
# Setup hypertable from options
|
28
33
|
# @see create_table with the hypertable options.
|
29
34
|
def create_hypertable(table_name,
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
time_column: 'created_at',
|
36
|
+
chunk_time_interval: '1 week',
|
37
|
+
compress_segmentby: nil,
|
38
|
+
compress_orderby: 'created_at',
|
39
|
+
compression_interval: nil,
|
40
|
+
partition_column: nil,
|
41
|
+
number_partitions: nil,
|
42
|
+
**hypertable_options)
|
36
43
|
|
37
44
|
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
38
|
-
|
45
|
+
|
46
|
+
options = ["chunk_time_interval => INTERVAL '#{chunk_time_interval}'"]
|
47
|
+
options += hypertable_options.map { |k, v| "#{k} => #{quote(v)}" }
|
48
|
+
|
49
|
+
arguments = [
|
50
|
+
quote(table_name),
|
51
|
+
quote(time_column),
|
52
|
+
(quote(partition_column) if partition_column),
|
53
|
+
(number_partitions if partition_column),
|
54
|
+
*options
|
55
|
+
]
|
56
|
+
|
57
|
+
execute "SELECT create_hypertable(#{arguments.compact.join(', ')})"
|
39
58
|
|
40
59
|
if compress_segmentby
|
41
60
|
execute <<~SQL
|
@@ -68,5 +68,5 @@ module Timescaledb
|
|
68
68
|
end
|
69
69
|
|
70
70
|
|
71
|
+
Scenic::Adapters::Postgres.include(Timescaledb::Scenic::Extension)
|
71
72
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.include(Timescaledb::Scenic::MigrationHelpers)
|
72
|
-
Scenic::Adapters::Postgres.prepend(Timescaledb::Scenic::Extension)
|
@@ -5,31 +5,24 @@ module Timescaledb
|
|
5
5
|
module SchemaDumper
|
6
6
|
def tables(stream)
|
7
7
|
super # This will call #table for each table in the database
|
8
|
-
views(stream) unless defined?(Scenic) # Don't call this twice if we're using Scenic
|
9
8
|
|
10
9
|
return unless Timescaledb::Hypertable.table_exists?
|
11
10
|
|
12
11
|
timescale_hypertables(stream)
|
13
12
|
timescale_retention_policies(stream)
|
14
|
-
end
|
15
|
-
|
16
|
-
def views(stream)
|
17
|
-
return unless Timescaledb::ContinuousAggregates.table_exists?
|
18
|
-
|
19
13
|
timescale_continuous_aggregates(stream) # Define these before any Scenic views that might use them
|
20
|
-
super if defined?(super)
|
21
14
|
end
|
22
15
|
|
23
16
|
def timescale_hypertables(stream)
|
24
|
-
stream.puts # Insert a blank line above the hypertable definitions, for readability
|
25
|
-
|
26
17
|
sorted_hypertables.each do |hypertable|
|
27
|
-
|
18
|
+
timescale_hypertable(hypertable, stream)
|
28
19
|
end
|
29
20
|
end
|
30
21
|
|
31
22
|
def timescale_retention_policies(stream)
|
32
|
-
|
23
|
+
if sorted_hypertables.any? { |hypertable| hypertable.jobs.exists?(proc_name: "policy_retention") }
|
24
|
+
stream.puts # Insert a blank line above the retention policies, for readability
|
25
|
+
end
|
33
26
|
|
34
27
|
sorted_hypertables.each do |hypertable|
|
35
28
|
timescale_retention_policy(hypertable, stream)
|
@@ -39,13 +32,18 @@ module Timescaledb
|
|
39
32
|
private
|
40
33
|
|
41
34
|
def timescale_hypertable(hypertable, stream)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
35
|
+
time = hypertable.main_dimension
|
36
|
+
|
37
|
+
options = {
|
38
|
+
time_column: time.column_name,
|
39
|
+
chunk_time_interval: time.time_interval.inspect,
|
40
|
+
**timescale_compression_settings_for(hypertable),
|
41
|
+
**timescale_space_partition_for(hypertable),
|
42
|
+
**timescale_index_options_for(hypertable)
|
43
|
+
}
|
44
|
+
|
45
|
+
options = options.map { |k, v| "#{k}: #{v.to_json}" }.join(", ")
|
46
|
+
stream.puts %Q[ create_hypertable "#{hypertable.hypertable_name}", #{options}]
|
49
47
|
end
|
50
48
|
|
51
49
|
def timescale_retention_policy(hypertable, stream)
|
@@ -56,21 +54,64 @@ module Timescaledb
|
|
56
54
|
|
57
55
|
def timescale_compression_settings_for(hypertable)
|
58
56
|
compression_settings = hypertable.compression_settings.each_with_object({}) do |setting, compression_settings|
|
59
|
-
|
57
|
+
# It's possible to configure compression so that it is segmented by multiple
|
58
|
+
# columns. To make sure we capture that correctly, we'll treat them as an array.
|
59
|
+
compression_settings[:compress_segmentby] ||= []
|
60
|
+
compression_settings[:compress_orderby] ||= []
|
61
|
+
|
62
|
+
compression_settings[:compress_segmentby] << setting.attname if setting.segmentby_column_index
|
60
63
|
|
61
64
|
if setting.orderby_column_index
|
62
|
-
|
63
|
-
|
65
|
+
if setting.orderby_asc
|
66
|
+
direction = "ASC"
|
67
|
+
if setting.orderby_nullsfirst
|
68
|
+
direction += " NULLS FIRST"
|
69
|
+
end
|
70
|
+
else
|
71
|
+
direction = "DESC"
|
72
|
+
if !setting.orderby_nullsfirst
|
73
|
+
direction += " NULLS LAST"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
compression_settings[:compress_orderby] << "#{setting.attname} #{direction}"
|
64
78
|
end
|
65
79
|
end
|
66
80
|
|
67
81
|
hypertable.jobs.compression.each do |job|
|
68
82
|
compression_settings[:compression_interval] = job.config["compress_after"]
|
69
83
|
end
|
84
|
+
|
85
|
+
# Pack the compression setting arrays into a comma-separated string instead.
|
86
|
+
if compression_settings[:compress_segmentby]
|
87
|
+
compression_settings[:compress_segmentby] = compression_settings[:compress_segmentby].join(", ")
|
88
|
+
end
|
89
|
+
if compression_settings[:compress_orderby]
|
90
|
+
compression_settings[:compress_orderby] = compression_settings[:compress_orderby].join(", ")
|
91
|
+
end
|
92
|
+
|
70
93
|
compression_settings
|
71
94
|
end
|
72
95
|
|
96
|
+
def timescale_space_partition_for(hypertable)
|
97
|
+
return {} unless hypertable.dimensions.length > 1
|
98
|
+
|
99
|
+
space = hypertable.dimensions.last
|
100
|
+
{partition_column: space.column_name, number_partitions: space.num_partitions}
|
101
|
+
end
|
102
|
+
|
103
|
+
def timescale_index_options_for(hypertable)
|
104
|
+
time = hypertable.main_dimension
|
105
|
+
if @connection.indexes(hypertable.hypertable_name).any? { |i| i.columns == [time.column_name] }
|
106
|
+
{}
|
107
|
+
else
|
108
|
+
{create_default_indexes: false}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
73
112
|
def timescale_continuous_aggregates(stream)
|
113
|
+
return unless Timescaledb::ContinuousAggregates.table_exists?
|
114
|
+
|
74
115
|
Timescaledb::ContinuousAggregates.all.each do |aggregate|
|
75
116
|
opts = if (refresh_policy = aggregate.jobs.refresh_continuous_aggregate.first)
|
76
117
|
interval = timescale_interval(refresh_policy.schedule_interval)
|
@@ -95,6 +136,7 @@ module Timescaledb
|
|
95
136
|
|
96
137
|
"INTERVAL '#{value}'"
|
97
138
|
end
|
139
|
+
|
98
140
|
def sorted_hypertables
|
99
141
|
@sorted_hypertables ||= Timescaledb::Hypertable.order(:hypertable_name).to_a
|
100
142
|
end
|
data/lib/timescaledb/version.rb
CHANGED
data/lib/timescaledb.rb
CHANGED
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.
|
4
|
+
version: 0.2.6
|
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:
|
11
|
+
date: 2023-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -144,6 +144,7 @@ executables:
|
|
144
144
|
extensions: []
|
145
145
|
extra_rdoc_files: []
|
146
146
|
files:
|
147
|
+
- ".github/workflows/ci.yml"
|
147
148
|
- ".gitignore"
|
148
149
|
- ".rspec"
|
149
150
|
- ".ruby-version"
|
@@ -240,6 +241,7 @@ files:
|
|
240
241
|
- lib/timescaledb/acts_as_hypertable.rb
|
241
242
|
- lib/timescaledb/acts_as_hypertable/core.rb
|
242
243
|
- lib/timescaledb/acts_as_time_vector.rb
|
244
|
+
- lib/timescaledb/application_record.rb
|
243
245
|
- lib/timescaledb/chunk.rb
|
244
246
|
- lib/timescaledb/compression_settings.rb
|
245
247
|
- lib/timescaledb/continuous_aggregates.rb
|