timescaledb 0.1.4 → 0.2.1
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/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +6 -3
- data/Gemfile.scenic +7 -0
- data/Gemfile.scenic.lock +121 -0
- data/README.md +35 -18
- data/Rakefile +7 -1
- data/bin/console +3 -3
- data/bin/setup +2 -0
- data/bin/tsdb +7 -7
- data/examples/{Gemfile → all_in_one/Gemfile} +0 -0
- data/examples/{Gemfile.lock → all_in_one/Gemfile.lock} +0 -0
- data/examples/{all_in_one.rb → all_in_one/all_in_one.rb} +1 -1
- data/examples/ranking/.gitattributes +7 -0
- data/examples/ranking/.gitignore +29 -0
- data/examples/ranking/.ruby-version +1 -0
- data/examples/ranking/Gemfile +33 -0
- data/examples/ranking/Gemfile.lock +189 -0
- data/examples/ranking/README.md +166 -0
- data/examples/ranking/Rakefile +6 -0
- data/examples/ranking/app/controllers/application_controller.rb +2 -0
- data/examples/ranking/app/controllers/concerns/.keep +0 -0
- data/examples/ranking/app/jobs/application_job.rb +7 -0
- data/examples/ranking/app/models/application_record.rb +3 -0
- data/examples/ranking/app/models/concerns/.keep +0 -0
- data/examples/ranking/app/models/game.rb +2 -0
- data/examples/ranking/app/models/play.rb +7 -0
- data/examples/ranking/bin/bundle +114 -0
- data/examples/ranking/bin/rails +4 -0
- data/examples/ranking/bin/rake +4 -0
- data/examples/ranking/bin/setup +33 -0
- data/examples/ranking/config/application.rb +39 -0
- data/examples/ranking/config/boot.rb +4 -0
- data/examples/ranking/config/credentials.yml.enc +1 -0
- data/examples/ranking/config/database.yml +86 -0
- data/examples/ranking/config/environment.rb +5 -0
- data/examples/ranking/config/environments/development.rb +60 -0
- data/examples/ranking/config/environments/production.rb +75 -0
- data/examples/ranking/config/environments/test.rb +53 -0
- data/examples/ranking/config/initializers/cors.rb +16 -0
- data/examples/ranking/config/initializers/filter_parameter_logging.rb +8 -0
- data/examples/ranking/config/initializers/inflections.rb +16 -0
- data/examples/ranking/config/initializers/timescale.rb +2 -0
- data/examples/ranking/config/locales/en.yml +33 -0
- data/examples/ranking/config/puma.rb +43 -0
- data/examples/ranking/config/routes.rb +6 -0
- data/examples/ranking/config/storage.yml +34 -0
- data/examples/ranking/config.ru +6 -0
- data/examples/ranking/db/migrate/20220209120747_create_games.rb +10 -0
- data/examples/ranking/db/migrate/20220209120910_create_plays.rb +19 -0
- data/examples/ranking/db/migrate/20220209143347_create_score_per_hours.rb +5 -0
- data/examples/ranking/db/schema.rb +47 -0
- data/examples/ranking/db/seeds.rb +7 -0
- data/examples/ranking/db/views/score_per_hours_v01.sql +7 -0
- data/examples/ranking/lib/tasks/.keep +0 -0
- data/examples/ranking/log/.keep +0 -0
- data/examples/ranking/public/robots.txt +1 -0
- data/examples/ranking/storage/.keep +0 -0
- data/examples/ranking/tmp/.keep +0 -0
- data/examples/ranking/tmp/pids/.keep +0 -0
- data/examples/ranking/tmp/storage/.keep +0 -0
- data/examples/ranking/vendor/.keep +0 -0
- data/lib/{timescale → timescaledb}/acts_as_hypertable/core.rb +1 -1
- data/lib/{timescale → timescaledb}/acts_as_hypertable.rb +6 -6
- data/lib/{timescale → timescaledb}/chunk.rb +1 -1
- data/lib/{timescale → timescaledb}/compression_settings.rb +3 -2
- data/lib/{timescale → timescaledb}/continuous_aggregates.rb +5 -4
- data/lib/timescaledb/dimensions.rb +6 -0
- data/lib/{timescale → timescaledb}/hypertable.rb +5 -5
- data/lib/timescaledb/job.rb +10 -0
- data/lib/{timescale → timescaledb}/job_stats.rb +3 -4
- data/lib/{timescale → timescaledb}/migration_helpers.rb +51 -13
- data/lib/timescaledb/scenic/adapter.rb +55 -0
- data/lib/timescaledb/scenic/extension.rb +72 -0
- data/lib/timescaledb/schema_dumper.rb +91 -0
- data/lib/{timescale → timescaledb}/stats_report.rb +2 -2
- data/lib/timescaledb/version.rb +3 -0
- data/lib/timescaledb.rb +64 -0
- data/{timescale.gemspec → timescaledb.gemspec} +5 -4
- metadata +92 -23
- data/lib/timescale/dimensions.rb +0 -7
- data/lib/timescale/job.rb +0 -13
- data/lib/timescale/schema_dumper.rb +0 -24
- data/lib/timescale/version.rb +0 -3
- data/lib/timescale.rb +0 -50
@@ -1,11 +1,9 @@
|
|
1
|
-
module
|
2
|
-
class
|
1
|
+
module Timescaledb
|
2
|
+
class JobStat < ActiveRecord::Base
|
3
3
|
self.table_name = "timescaledb_information.job_stats"
|
4
4
|
|
5
5
|
belongs_to :job
|
6
6
|
|
7
|
-
attribute :last_run_duration, :interval
|
8
|
-
|
9
7
|
scope :success, -> { where(last_run_status: "Success") }
|
10
8
|
scope :scheduled, -> { where(job_status: "Scheduled") }
|
11
9
|
scope :resume, -> do
|
@@ -15,4 +13,5 @@ module Timescale
|
|
15
13
|
.to_a.map{|e|e.attributes.transform_keys(&:to_sym) }
|
16
14
|
end
|
17
15
|
end
|
16
|
+
JobStats = JobStat
|
18
17
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'active_record/connection_adapters/postgresql_adapter'
|
2
2
|
|
3
3
|
# Useful methods to run TimescaleDB in you Ruby app.
|
4
|
-
module
|
4
|
+
module Timescaledb
|
5
5
|
# Migration helpers can help you to setup hypertables by default.
|
6
6
|
module MigrationHelpers
|
7
7
|
# create_table can receive `hypertable` argument
|
@@ -51,25 +51,63 @@ module Timescale
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
|
54
|
+
# Create a new continuous aggregate
|
55
|
+
#
|
56
|
+
# @param name [String, Symbol] The name of the continuous aggregate.
|
57
|
+
# @param query [String] The SQL query for the aggregate view definition.
|
58
|
+
# @param with_data [Boolean] Set to true to create the aggregate WITH DATA
|
59
|
+
# @param refresh_policies [Hash] Set to create a refresh policy
|
60
|
+
# @option refresh_policies [String] start_offset: INTERVAL or integer
|
61
|
+
# @option refresh_policies [String] end_offset: INTERVAL or integer
|
62
|
+
# @option refresh_policies [String] schedule_interval: INTERVAL
|
63
|
+
#
|
64
|
+
# @see https://docs.timescale.com/api/latest/continuous-aggregates/add_continuous_aggregate_policy/
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# create_continuous_aggregate(:activity_counts, query: <<-SQL, refresh_policies: { schedule_interval: "INTERVAL '1 hour'" })
|
68
|
+
# SELECT
|
69
|
+
# time_bucket(INTERVAL '1 day', activity.created_at) AS bucket,
|
70
|
+
# count(*)
|
71
|
+
# FROM activity
|
72
|
+
# GROUP BY bucket
|
73
|
+
# SQL
|
74
|
+
#
|
75
|
+
def create_continuous_aggregate(table_name, query, **options)
|
55
76
|
execute <<~SQL
|
56
|
-
CREATE MATERIALIZED VIEW #{
|
77
|
+
CREATE MATERIALIZED VIEW #{table_name}
|
57
78
|
WITH (timescaledb.continuous) AS
|
58
79
|
#{query.respond_to?(:to_sql) ? query.to_sql : query}
|
59
80
|
WITH #{"NO" unless options[:with_data]} DATA;
|
60
81
|
SQL
|
61
82
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
83
|
+
create_continuous_aggregate_policy(table_name, options[:refresh_policies] || {})
|
84
|
+
end
|
85
|
+
alias_method :create_continuous_aggregates, :create_continuous_aggregate
|
86
|
+
|
87
|
+
def create_continuous_aggregate_policy(table_name, **options)
|
88
|
+
return if options.empty?
|
89
|
+
|
90
|
+
# TODO: assert valid keys
|
91
|
+
execute <<~SQL
|
92
|
+
SELECT add_continuous_aggregate_policy('#{table_name}',
|
93
|
+
start_offset => #{options[:start_offset]},
|
94
|
+
end_offset => #{options[:end_offset]},
|
95
|
+
schedule_interval => #{options[:schedule_interval]});
|
96
|
+
SQL
|
97
|
+
end
|
98
|
+
|
99
|
+
def remove_continuous_aggregate_policy(table_name)
|
100
|
+
execute "SELECT remove_continuous_aggregate_policy('#{table_name}')"
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_retention_policy(table_name, interval:)
|
104
|
+
execute "SELECT add_retention_policy('#{table_name}', INTERVAL '#{interval}')"
|
105
|
+
end
|
106
|
+
|
107
|
+
def remove_retention_policy(table_name)
|
108
|
+
execute "SELECT remove_retention_policy('#{table_name}')"
|
71
109
|
end
|
72
110
|
end
|
73
111
|
end
|
74
112
|
|
75
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.include(
|
113
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.include(Timescaledb::MigrationHelpers)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'scenic/adapters/postgres'
|
2
|
+
require 'scenic/adapters/postgres/views'
|
3
|
+
|
4
|
+
module Timescaledb
|
5
|
+
module Scenic
|
6
|
+
class Views < ::Scenic::Adapters::Postgres::Views
|
7
|
+
# All of the views that this connection has defined, excluding any
|
8
|
+
# Timescale continuous aggregates. Those should be defined using
|
9
|
+
# +create_continuous_aggregate+ rather than +create_view+.
|
10
|
+
#
|
11
|
+
# @return [Array<Scenic::View>]
|
12
|
+
def all
|
13
|
+
ts_views = views_from_timescale.map { |v| to_scenic_view(v) }
|
14
|
+
pg_views = views_from_postgres.map { |v| to_scenic_view(v) }
|
15
|
+
ts_view_names = ts_views.map(&:name)
|
16
|
+
# Skip records with matching names (includes the schema name
|
17
|
+
# for records not in the public schema)
|
18
|
+
pg_views.reject { |v| v.name.in?(ts_view_names) }
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def views_from_timescale
|
24
|
+
connection.execute(<<-SQL.squish)
|
25
|
+
SELECT
|
26
|
+
view_name as viewname,
|
27
|
+
view_definition AS definition,
|
28
|
+
'm' AS kind,
|
29
|
+
view_schema AS namespace
|
30
|
+
FROM timescaledb_information.continuous_aggregates
|
31
|
+
SQL
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Adapter < ::Scenic::Adapters::Postgres
|
36
|
+
# Timescale does some funky stuff under the hood with continuous
|
37
|
+
# aggregates. A continuous aggregate is made up of:
|
38
|
+
#
|
39
|
+
# 1. A hypertable to store the materialized data
|
40
|
+
# 2. An entry in the jobs table to refresh the data
|
41
|
+
# 3. A view definition that union's the hypertable and any recent data
|
42
|
+
# not included in the hypertable
|
43
|
+
#
|
44
|
+
# That doesn't dump well, even to structure.sql (we lose the job
|
45
|
+
# definition, since it's not part of the DDL).
|
46
|
+
#
|
47
|
+
# Our schema dumper implementation will handle dumping the continuous
|
48
|
+
# aggregate definitions, but we need to override Scenic's schema dumping
|
49
|
+
# to exclude those continuous aggregates.
|
50
|
+
def views
|
51
|
+
Views.new(connection).all
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Scenic does not include `WITH` option that is used with continuous aggregates.
|
2
|
+
module Timescaledb
|
3
|
+
module Scenic
|
4
|
+
module Extension
|
5
|
+
# @override Scenic::Adapters::Postgres#create_materialized_view
|
6
|
+
# Creates a materialized view in the database
|
7
|
+
#
|
8
|
+
# @param name The name of the materialized view to create
|
9
|
+
# @param sql_definition The SQL schema that defines the materialized view.
|
10
|
+
# @param with [String] Default: nil. Set with: "..." to add "WITH (...)".
|
11
|
+
# @param no_data [Boolean] Default: false. Set to true to not create data.
|
12
|
+
# materialized view without running the associated query. You will need
|
13
|
+
# to perform a non-concurrent refresh to populate with data.
|
14
|
+
#
|
15
|
+
# This is typically called in a migration via {Statements#create_view}.
|
16
|
+
# @return [void]
|
17
|
+
def create_materialized_view(name, sql_definition, with: nil, no_data: false)
|
18
|
+
execute <<-SQL
|
19
|
+
CREATE MATERIALIZED VIEW #{quote_table_name(name)}
|
20
|
+
#{"WITH (#{with})" if with} AS
|
21
|
+
#{sql_definition.rstrip.chomp(';')}
|
22
|
+
#{'WITH NO DATA' if no_data};
|
23
|
+
SQL
|
24
|
+
end
|
25
|
+
|
26
|
+
# @override Scenic::Adapters::Postgres#create_view
|
27
|
+
# to add the `with: ` keyword that can be used for such option.
|
28
|
+
#
|
29
|
+
def create_view(name, version: nil, with: nil, sql_definition: nil, materialized: false, no_data: false)
|
30
|
+
if version.present? && sql_definition.present?
|
31
|
+
raise(
|
32
|
+
ArgumentError,
|
33
|
+
"sql_definition and version cannot both be set",
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
if version.blank? && sql_definition.blank?
|
38
|
+
version = 1
|
39
|
+
end
|
40
|
+
|
41
|
+
sql_definition ||= definition(name, version)
|
42
|
+
|
43
|
+
if materialized
|
44
|
+
::Scenic.database.create_materialized_view(
|
45
|
+
name,
|
46
|
+
sql_definition,
|
47
|
+
no_data: no_data,
|
48
|
+
with: with
|
49
|
+
)
|
50
|
+
else
|
51
|
+
::Scenic.database.create_view(name, sql_definition, with: with)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def definition(name, version)
|
58
|
+
::Scenic::Definition.new(name, version).to_sql
|
59
|
+
end
|
60
|
+
end
|
61
|
+
module MigrationHelpers
|
62
|
+
# Create a timescale continuous aggregate view
|
63
|
+
def create_scenic_continuous_aggregate(name)
|
64
|
+
::Scenic.database.create_view(name, materialized: true, no_data: true, with: "timescaledb.continuous")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.include(Timescaledb::Scenic::MigrationHelpers)
|
72
|
+
Scenic::Adapters::Postgres.prepend(Timescaledb::Scenic::Extension)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
2
|
+
require 'active_support/core_ext/string/indent'
|
3
|
+
|
4
|
+
module Timescaledb
|
5
|
+
module SchemaDumper
|
6
|
+
def tables(stream)
|
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
|
+
end
|
10
|
+
|
11
|
+
def table(table_name, stream)
|
12
|
+
super(table_name, stream)
|
13
|
+
if Timescaledb::Hypertable.table_exists? &&
|
14
|
+
(hypertable = Timescaledb::Hypertable.find_by(hypertable_name: table_name))
|
15
|
+
timescale_hypertable(hypertable, stream)
|
16
|
+
timescale_retention_policy(hypertable, stream)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def views(stream)
|
21
|
+
return unless Timescaledb::ContinuousAggregates.table_exists?
|
22
|
+
|
23
|
+
timescale_continuous_aggregates(stream) # Define these before any Scenic views that might use them
|
24
|
+
super if defined?(super)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def timescale_hypertable(hypertable, stream)
|
30
|
+
dim = hypertable.dimensions
|
31
|
+
extra_settings = {
|
32
|
+
time_column: "#{dim.column_name}",
|
33
|
+
chunk_time_interval: "#{dim.time_interval.inspect}"
|
34
|
+
}.merge(timescale_compression_settings_for(hypertable)).map {|k, v| %Q[#{k}: "#{v}"]}.join(", ")
|
35
|
+
|
36
|
+
stream.puts %Q[ create_hypertable "#{hypertable.hypertable_name}", #{extra_settings}]
|
37
|
+
stream.puts
|
38
|
+
end
|
39
|
+
|
40
|
+
def timescale_retention_policy(hypertable, stream)
|
41
|
+
hypertable.jobs.where(proc_name: "policy_retention").each do |job|
|
42
|
+
stream.puts %Q[ create_retention_policy "#{job.hypertable_name}", interval: "#{job.config["drop_after"]}"]
|
43
|
+
stream.puts
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def timescale_compression_settings_for(hypertable)
|
48
|
+
compression_settings = hypertable.compression_settings.each_with_object({}) do |setting, compression_settings|
|
49
|
+
compression_settings[:compress_segmentby] = setting.attname if setting.segmentby_column_index
|
50
|
+
|
51
|
+
if setting.orderby_column_index
|
52
|
+
direction = setting.orderby_asc ? "ASC" : "DESC"
|
53
|
+
compression_settings[:compress_orderby] = "#{setting.attname} #{direction}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
hypertable.jobs.compression.each do |job|
|
58
|
+
compression_settings[:compression_interval] = job.config["compress_after"]
|
59
|
+
end
|
60
|
+
compression_settings
|
61
|
+
end
|
62
|
+
|
63
|
+
def timescale_continuous_aggregates(stream)
|
64
|
+
Timescaledb::ContinuousAggregates.all.each do |aggregate|
|
65
|
+
opts = if (refresh_policy = aggregate.jobs.refresh_continuous_aggregate.first)
|
66
|
+
interval = timescale_interval(refresh_policy.schedule_interval)
|
67
|
+
end_offset = timescale_interval(refresh_policy.config["end_offset"])
|
68
|
+
start_offset = timescale_interval(refresh_policy.config["start_offset"])
|
69
|
+
%Q[, refresh_policies: { start_offset: "#{start_offset}", end_offset: "#{end_offset}", schedule_interval: "#{interval}"}]
|
70
|
+
else
|
71
|
+
""
|
72
|
+
end
|
73
|
+
|
74
|
+
stream.puts <<~AGG.indent(2)
|
75
|
+
create_continuous_aggregate("#{aggregate.view_name}", <<-SQL#{opts})
|
76
|
+
#{aggregate.view_definition.strip.gsub(/;$/, "")}
|
77
|
+
SQL
|
78
|
+
AGG
|
79
|
+
stream.puts
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def timescale_interval(value)
|
84
|
+
return "NULL" if value.nil? || value.to_s.downcase == "null"
|
85
|
+
|
86
|
+
"INTERVAL '#{value}'"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend(Timescaledb::SchemaDumper)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require "active_support/core_ext/numeric/conversions"
|
2
2
|
|
3
|
-
module
|
3
|
+
module Timescaledb
|
4
4
|
module StatsReport
|
5
5
|
module_function
|
6
6
|
def resume(scope=Hypertable.all)
|
@@ -19,7 +19,7 @@ module Timescale
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def compression_resume(scope)
|
22
|
-
sum = -> (method) { (scope.map(&method).inject(:+) || 0).
|
22
|
+
sum = -> (method) { (scope.map(&method).inject(:+) || 0).to_formatted_s(:human_size)}
|
23
23
|
{
|
24
24
|
uncompressed: sum[:before_total_bytes],
|
25
25
|
compressed: sum[:after_total_bytes]
|
data/lib/timescaledb.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
require_relative 'timescaledb/acts_as_hypertable'
|
4
|
+
require_relative 'timescaledb/acts_as_hypertable/core'
|
5
|
+
require_relative 'timescaledb/chunk'
|
6
|
+
require_relative 'timescaledb/compression_settings'
|
7
|
+
require_relative 'timescaledb/continuous_aggregates'
|
8
|
+
require_relative 'timescaledb/dimensions'
|
9
|
+
require_relative 'timescaledb/hypertable'
|
10
|
+
require_relative 'timescaledb/job'
|
11
|
+
require_relative 'timescaledb/job_stats'
|
12
|
+
require_relative 'timescaledb/schema_dumper'
|
13
|
+
require_relative 'timescaledb/stats_report'
|
14
|
+
require_relative 'timescaledb/migration_helpers'
|
15
|
+
require_relative 'timescaledb/version'
|
16
|
+
|
17
|
+
module Timescaledb
|
18
|
+
module_function
|
19
|
+
|
20
|
+
def chunks
|
21
|
+
Chunk.all
|
22
|
+
end
|
23
|
+
|
24
|
+
def hypertables
|
25
|
+
Hypertable.all
|
26
|
+
end
|
27
|
+
|
28
|
+
def continuous_aggregates
|
29
|
+
ContinuousAggregates.all
|
30
|
+
end
|
31
|
+
|
32
|
+
def compression_settings
|
33
|
+
CompressionSettings.all
|
34
|
+
end
|
35
|
+
|
36
|
+
def jobs
|
37
|
+
Job.all
|
38
|
+
end
|
39
|
+
|
40
|
+
def job_stats
|
41
|
+
JobStats.all
|
42
|
+
end
|
43
|
+
|
44
|
+
def stats(scope=Hypertable.all)
|
45
|
+
StatsReport.resume(scope)
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_hypertable_options
|
49
|
+
Timescaledb::ActsAsHypertable::DEFAULT_OPTIONS
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
require 'scenic'
|
55
|
+
require_relative 'timescaledb/scenic/adapter'
|
56
|
+
require_relative 'timescaledb/scenic/extension'
|
57
|
+
|
58
|
+
Scenic.configure do |config|
|
59
|
+
config.database = Timescaledb::Scenic::Adapter.new
|
60
|
+
end
|
61
|
+
|
62
|
+
rescue LoadError
|
63
|
+
# This is expected when the scenic gem is not being used
|
64
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require_relative 'lib/
|
1
|
+
require_relative 'lib/timescaledb/version'
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "timescaledb"
|
5
|
-
spec.version =
|
5
|
+
spec.version = Timescaledb::VERSION
|
6
6
|
spec.authors = ["Jônatas Davi Paganini"]
|
7
7
|
spec.email = ["jonatasdp@gmail.com"]
|
8
8
|
|
9
9
|
spec.summary = %q{TimescaleDB helpers for Ruby ecosystem.}
|
10
10
|
spec.description = %q{Functions from timescaledb available in the ActiveRecord models.}
|
11
|
-
spec.homepage = "https://github.com/jonatas/
|
11
|
+
spec.homepage = "https://github.com/jonatas/timescaledb"
|
12
12
|
spec.license = "MIT"
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
14
|
|
@@ -27,8 +27,9 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^bin/tsdb}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
-
spec.add_dependency
|
30
|
+
spec.add_dependency "pg", "~> 1.2"
|
31
31
|
spec.add_dependency "activerecord"
|
32
|
+
spec.add_dependency "activesupport"
|
32
33
|
|
33
34
|
spec.add_development_dependency "pry"
|
34
35
|
spec.add_development_dependency "rspec-its"
|
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
|
4
|
+
version: 0.2.1
|
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: 2022-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: pry
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -132,40 +146,95 @@ extra_rdoc_files: []
|
|
132
146
|
files:
|
133
147
|
- ".gitignore"
|
134
148
|
- ".rspec"
|
149
|
+
- ".ruby-version"
|
150
|
+
- ".tool-versions"
|
135
151
|
- ".travis.yml"
|
136
152
|
- CODE_OF_CONDUCT.md
|
137
153
|
- Gemfile
|
138
154
|
- Gemfile.lock
|
155
|
+
- Gemfile.scenic
|
156
|
+
- Gemfile.scenic.lock
|
139
157
|
- LICENSE.txt
|
140
158
|
- README.md
|
141
159
|
- Rakefile
|
142
160
|
- bin/console
|
143
161
|
- bin/setup
|
144
162
|
- bin/tsdb
|
145
|
-
- examples/Gemfile
|
146
|
-
- examples/Gemfile.lock
|
147
|
-
- examples/all_in_one.rb
|
148
|
-
-
|
149
|
-
-
|
150
|
-
-
|
151
|
-
-
|
152
|
-
-
|
153
|
-
-
|
154
|
-
-
|
155
|
-
-
|
156
|
-
-
|
157
|
-
-
|
158
|
-
-
|
159
|
-
-
|
160
|
-
-
|
161
|
-
-
|
162
|
-
-
|
163
|
-
|
163
|
+
- examples/all_in_one/Gemfile
|
164
|
+
- examples/all_in_one/Gemfile.lock
|
165
|
+
- examples/all_in_one/all_in_one.rb
|
166
|
+
- examples/ranking/.gitattributes
|
167
|
+
- examples/ranking/.gitignore
|
168
|
+
- examples/ranking/.ruby-version
|
169
|
+
- examples/ranking/Gemfile
|
170
|
+
- examples/ranking/Gemfile.lock
|
171
|
+
- examples/ranking/README.md
|
172
|
+
- examples/ranking/Rakefile
|
173
|
+
- examples/ranking/app/controllers/application_controller.rb
|
174
|
+
- examples/ranking/app/controllers/concerns/.keep
|
175
|
+
- examples/ranking/app/jobs/application_job.rb
|
176
|
+
- examples/ranking/app/models/application_record.rb
|
177
|
+
- examples/ranking/app/models/concerns/.keep
|
178
|
+
- examples/ranking/app/models/game.rb
|
179
|
+
- examples/ranking/app/models/play.rb
|
180
|
+
- examples/ranking/bin/bundle
|
181
|
+
- examples/ranking/bin/rails
|
182
|
+
- examples/ranking/bin/rake
|
183
|
+
- examples/ranking/bin/setup
|
184
|
+
- examples/ranking/config.ru
|
185
|
+
- examples/ranking/config/application.rb
|
186
|
+
- examples/ranking/config/boot.rb
|
187
|
+
- examples/ranking/config/credentials.yml.enc
|
188
|
+
- examples/ranking/config/database.yml
|
189
|
+
- examples/ranking/config/environment.rb
|
190
|
+
- examples/ranking/config/environments/development.rb
|
191
|
+
- examples/ranking/config/environments/production.rb
|
192
|
+
- examples/ranking/config/environments/test.rb
|
193
|
+
- examples/ranking/config/initializers/cors.rb
|
194
|
+
- examples/ranking/config/initializers/filter_parameter_logging.rb
|
195
|
+
- examples/ranking/config/initializers/inflections.rb
|
196
|
+
- examples/ranking/config/initializers/timescale.rb
|
197
|
+
- examples/ranking/config/locales/en.yml
|
198
|
+
- examples/ranking/config/puma.rb
|
199
|
+
- examples/ranking/config/routes.rb
|
200
|
+
- examples/ranking/config/storage.yml
|
201
|
+
- examples/ranking/db/migrate/20220209120747_create_games.rb
|
202
|
+
- examples/ranking/db/migrate/20220209120910_create_plays.rb
|
203
|
+
- examples/ranking/db/migrate/20220209143347_create_score_per_hours.rb
|
204
|
+
- examples/ranking/db/schema.rb
|
205
|
+
- examples/ranking/db/seeds.rb
|
206
|
+
- examples/ranking/db/views/score_per_hours_v01.sql
|
207
|
+
- examples/ranking/lib/tasks/.keep
|
208
|
+
- examples/ranking/log/.keep
|
209
|
+
- examples/ranking/public/robots.txt
|
210
|
+
- examples/ranking/storage/.keep
|
211
|
+
- examples/ranking/tmp/.keep
|
212
|
+
- examples/ranking/tmp/pids/.keep
|
213
|
+
- examples/ranking/tmp/storage/.keep
|
214
|
+
- examples/ranking/vendor/.keep
|
215
|
+
- lib/timescaledb.rb
|
216
|
+
- lib/timescaledb/acts_as_hypertable.rb
|
217
|
+
- lib/timescaledb/acts_as_hypertable/core.rb
|
218
|
+
- lib/timescaledb/chunk.rb
|
219
|
+
- lib/timescaledb/compression_settings.rb
|
220
|
+
- lib/timescaledb/continuous_aggregates.rb
|
221
|
+
- lib/timescaledb/dimensions.rb
|
222
|
+
- lib/timescaledb/hypertable.rb
|
223
|
+
- lib/timescaledb/job.rb
|
224
|
+
- lib/timescaledb/job_stats.rb
|
225
|
+
- lib/timescaledb/migration_helpers.rb
|
226
|
+
- lib/timescaledb/scenic/adapter.rb
|
227
|
+
- lib/timescaledb/scenic/extension.rb
|
228
|
+
- lib/timescaledb/schema_dumper.rb
|
229
|
+
- lib/timescaledb/stats_report.rb
|
230
|
+
- lib/timescaledb/version.rb
|
231
|
+
- timescaledb.gemspec
|
232
|
+
homepage: https://github.com/jonatas/timescaledb
|
164
233
|
licenses:
|
165
234
|
- MIT
|
166
235
|
metadata:
|
167
236
|
allowed_push_host: https://rubygems.org
|
168
|
-
homepage_uri: https://github.com/jonatas/
|
237
|
+
homepage_uri: https://github.com/jonatas/timescaledb
|
169
238
|
post_install_message:
|
170
239
|
rdoc_options: []
|
171
240
|
require_paths:
|
@@ -181,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
250
|
- !ruby/object:Gem::Version
|
182
251
|
version: '0'
|
183
252
|
requirements: []
|
184
|
-
rubygems_version: 3.
|
253
|
+
rubygems_version: 3.1.2
|
185
254
|
signing_key:
|
186
255
|
specification_version: 4
|
187
256
|
summary: TimescaleDB helpers for Ruby ecosystem.
|
data/lib/timescale/dimensions.rb
DELETED
data/lib/timescale/job.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
module Timescale
|
2
|
-
class Job < ActiveRecord::Base
|
3
|
-
self.table_name = "timescaledb_information.jobs"
|
4
|
-
self.primary_key = "job_id"
|
5
|
-
|
6
|
-
attribute :schedule_interval, :interval
|
7
|
-
attribute :max_runtime, :interval
|
8
|
-
attribute :retry_period, :interval
|
9
|
-
|
10
|
-
scope :compression, -> { where(proc_name: "tsbs_compress_chunks") }
|
11
|
-
scope :scheduled, -> { where(scheduled: true) }
|
12
|
-
end
|
13
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.class_eval do
|
2
|
-
def table(table_name, stream)
|
3
|
-
super(table_name, stream)
|
4
|
-
if hypertable=Timescale::Hypertable.find_by(hypertable_name: table_name)
|
5
|
-
dim = hypertable.dimensions
|
6
|
-
# TODO Build compression settings for the template:
|
7
|
-
# #{build_compression_settings_for(hypertable)})
|
8
|
-
stream.puts <<TEMPLATE
|
9
|
-
create_hypertable('#{table_name}',
|
10
|
-
time_column: '#{dim.column_name}',
|
11
|
-
chunk_time_interval: '#{dim.time_interval.inspect}')
|
12
|
-
TEMPLATE
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
=begin
|
18
|
-
def build_compression_settings_for(hypertable)
|
19
|
-
return if hypertable.compression_settings.nil?
|
20
|
-
hypertable.compression_settings.map do |settings|
|
21
|
-
", compress_segmentby: #{settings.segmentby_column_index},
|
22
|
-
compress_orderby: 'created_at',
|
23
|
-
compression_interval: nil)
|
24
|
-
=end
|
data/lib/timescale/version.rb
DELETED