influxer 1.1.6 → 1.2.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 +4 -4
- data/.rubocop.yml +34 -58
- data/.travis.yml +6 -1
- data/Changelog.md +6 -2
- data/Gemfile +5 -2
- data/MIT-LICENSE +1 -1
- data/README.md +21 -21
- data/Rakefile +4 -2
- data/bin/console +8 -0
- data/gemfiles/rails32.gemfile +1 -1
- data/gemfiles/rails42.gemfile +1 -1
- data/gemfiles/rails5.gemfile +2 -2
- data/gemfiles/rails6.gemfile +7 -0
- data/influxer.gemspec +16 -9
- data/lib/influxer.rb +10 -9
- data/lib/influxer/client.rb +1 -1
- data/lib/influxer/config.rb +3 -3
- data/lib/influxer/engine.rb +1 -1
- data/lib/influxer/metrics/active_model3/model.rb +2 -4
- data/lib/influxer/metrics/metrics.rb +8 -8
- data/lib/influxer/metrics/quoting/timestamp.rb +13 -13
- data/lib/influxer/metrics/relation.rb +17 -13
- data/lib/influxer/metrics/relation/calculations.rb +1 -1
- data/lib/influxer/metrics/relation/time_query.rb +15 -14
- data/lib/influxer/metrics/relation/where_clause.rb +6 -4
- data/lib/influxer/metrics/scoping.rb +4 -4
- data/lib/influxer/metrics/scoping/current_scope.rb +2 -1
- data/lib/influxer/metrics/scoping/default.rb +1 -1
- data/lib/influxer/metrics/scoping/named.rb +2 -1
- data/lib/influxer/model.rb +4 -9
- data/lib/influxer/rails/client.rb +1 -1
- data/lib/influxer/version.rb +1 -1
- data/spec/cases/points_spec.rb +4 -4
- data/spec/cases/write_points_spec.rb +9 -9
- data/spec/client_spec.rb +4 -4
- data/spec/metrics/metrics_spec.rb +16 -16
- data/spec/metrics/relation_spec.rb +11 -11
- data/spec/metrics/scoping_spec.rb +2 -2
- data/spec/model/user_spec.rb +2 -2
- data/spec/spec_helper.rb +13 -14
- data/spec/support/shared_contexts/shared_precision.rb +1 -1
- metadata +27 -63
@@ -1,16 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "influxer/metrics/relation"
|
4
|
+
require "influxer/metrics/scoping"
|
5
|
+
require "influxer/metrics/quoting/timestamp"
|
6
|
+
require "influxer/metrics/active_model3/model"
|
7
7
|
|
8
8
|
module Influxer
|
9
9
|
class MetricsError < StandardError; end
|
10
10
|
class MetricsInvalid < MetricsError; end
|
11
11
|
|
12
12
|
# Base class for InfluxDB querying and writing
|
13
|
-
# rubocop:disable Metrics/ClassLength
|
14
13
|
class Metrics
|
15
14
|
TIME_FACTOR = 1_000_000_000
|
16
15
|
if Influxer.active_model3?
|
@@ -124,7 +123,7 @@ module Influxer
|
|
124
123
|
quoted_series(val.call(instance), write: write)
|
125
124
|
when Array
|
126
125
|
if val.length > 1
|
127
|
-
"merge(#{val.map { |s| quoted_series(s, write: write) }.join(
|
126
|
+
"merge(#{val.map { |s| quoted_series(s, write: write) }.join(",")})"
|
128
127
|
else
|
129
128
|
quoted_series(val.first, write: write)
|
130
129
|
end
|
@@ -132,7 +131,7 @@ module Influxer
|
|
132
131
|
# Only add retention policy when selecting points
|
133
132
|
# and not writing
|
134
133
|
if !write && retention_policy.present?
|
135
|
-
[quote(@retention_policy), quote(val)].join(
|
134
|
+
[quote(@retention_policy), quote(val)].join(".")
|
136
135
|
else
|
137
136
|
quote(val)
|
138
137
|
end
|
@@ -168,6 +167,7 @@ module Influxer
|
|
168
167
|
|
169
168
|
def write!
|
170
169
|
raise MetricsInvalid if invalid?
|
170
|
+
|
171
171
|
write
|
172
172
|
end
|
173
173
|
|
@@ -228,7 +228,7 @@ module Influxer
|
|
228
228
|
end
|
229
229
|
|
230
230
|
def unquote(name)
|
231
|
-
name.gsub(/(\A['"]|['"]\z)/,
|
231
|
+
name.gsub(/(\A['"]|['"]\z)/, "")
|
232
232
|
end
|
233
233
|
end
|
234
234
|
end
|
@@ -3,27 +3,27 @@
|
|
3
3
|
module Influxer
|
4
4
|
module TimestampQuoting #:nodoc:
|
5
5
|
TIME_FACTORS = {
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
"ns" => 1_000_000_000,
|
7
|
+
"ms" => 1_000,
|
8
|
+
"s" => 1
|
9
9
|
}.freeze
|
10
10
|
|
11
|
-
DEFAULT_PRECISION =
|
11
|
+
DEFAULT_PRECISION = "ns"
|
12
12
|
|
13
13
|
# Quote timestamp
|
14
14
|
# rubocop: disable Metrics/MethodLength, Metrics/AbcSize
|
15
15
|
def quote_timestamp(val, client)
|
16
16
|
if Influxer.config.time_duration_suffix_enabled
|
17
|
-
precision = if TIME_FACTORS.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
precision = if TIME_FACTORS.key?(client.time_precision)
|
18
|
+
client.time_precision
|
19
|
+
else
|
20
|
+
DEFAULT_PRECISION
|
21
|
+
end
|
22
22
|
return quote_timestamp_with_suffix(val, precision)
|
23
23
|
end
|
24
24
|
|
25
|
-
if !TIME_FACTORS.
|
26
|
-
|
25
|
+
if !TIME_FACTORS.key?(client.time_precision) &&
|
26
|
+
!val.is_a?(Numeric)
|
27
27
|
warn(
|
28
28
|
"Influxer doesn't automatically cast Time and String values " \
|
29
29
|
"to '#{client.time_precision}' precision. " \
|
@@ -41,8 +41,8 @@ module Influxer
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def quote_timestamp_for_write(val, client)
|
44
|
-
if !TIME_FACTORS.
|
45
|
-
|
44
|
+
if !TIME_FACTORS.key?(client.time_precision) &&
|
45
|
+
!val.is_a?(Numeric)
|
46
46
|
raise ArgumentError,
|
47
47
|
"Influxer doesn't support quoting #{val} " \
|
48
48
|
" with '#{client.time_precision}' precision. " \
|
@@ -1,14 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
3
|
+
require "active_support/core_ext/module/delegation"
|
4
|
+
require "influxer/metrics/relation/time_query"
|
5
|
+
require "influxer/metrics/relation/calculations"
|
6
|
+
require "influxer/metrics/relation/where_clause"
|
7
|
+
require "influxer/metrics/quoting/timestamp"
|
8
8
|
|
9
9
|
module Influxer
|
10
10
|
# Relation is used to build queries
|
11
|
-
# rubocop:disable Metrics/ClassLength
|
12
11
|
class Relation
|
13
12
|
include Influxer::TimeQuery
|
14
13
|
include Influxer::Calculations
|
@@ -144,17 +143,17 @@ module Influxer
|
|
144
143
|
|
145
144
|
sql << "from #{build_series_name}"
|
146
145
|
|
147
|
-
sql << "where #{where_values.join(
|
146
|
+
sql << "where #{where_values.join(" and ")}" unless where_values.empty?
|
148
147
|
|
149
148
|
unless group_values.empty? && time_value.nil?
|
150
|
-
group_fields = (time_value.nil? ? [] : [
|
149
|
+
group_fields = (time_value.nil? ? [] : ["time(" + @values[:time] + ")"]) + group_values
|
151
150
|
group_fields.uniq!
|
152
|
-
sql << "group by #{group_fields.join(
|
151
|
+
sql << "group by #{group_fields.join(", ")}"
|
153
152
|
end
|
154
153
|
|
155
154
|
sql << "fill(#{fill_value})" unless fill_value.nil?
|
156
155
|
|
157
|
-
sql << "order by #{order_values.uniq.join(
|
156
|
+
sql << "order by #{order_values.uniq.join(",")}" unless order_values.empty?
|
158
157
|
|
159
158
|
sql << "limit #{limit_value}" unless limit_value.nil?
|
160
159
|
sql << "offset #{offset_value}" unless offset_value.nil?
|
@@ -169,14 +168,15 @@ module Influxer
|
|
169
168
|
|
170
169
|
def to_a
|
171
170
|
return @records if loaded?
|
171
|
+
|
172
172
|
load
|
173
173
|
end
|
174
174
|
|
175
175
|
def inspect
|
176
176
|
entries = to_a.take(11).map!(&:inspect)
|
177
|
-
entries[10] =
|
177
|
+
entries[10] = "..." if entries.size == 11
|
178
178
|
|
179
|
-
"#<#{self.class.name} [#{entries.join(
|
179
|
+
"#<#{self.class.name} [#{entries.join(", ")}]>"
|
180
180
|
end
|
181
181
|
|
182
182
|
def empty?
|
@@ -209,7 +209,7 @@ module Influxer
|
|
209
209
|
|
210
210
|
sql << "from #{@instance.series}"
|
211
211
|
|
212
|
-
sql << "where #{where_values.join(
|
212
|
+
sql << "where #{where_values.join(" and ")}" unless where_values.empty?
|
213
213
|
|
214
214
|
sql = sql.join " "
|
215
215
|
|
@@ -228,6 +228,7 @@ module Influxer
|
|
228
228
|
# rubocop:disable Metrics/MethodLength
|
229
229
|
def merge!(rel)
|
230
230
|
return self if rel.nil?
|
231
|
+
|
231
232
|
MULTI_VALUE_METHODS.each do |method|
|
232
233
|
(@values[method] ||= []).concat(rel.values[method]).uniq! unless rel.values[method].nil?
|
233
234
|
end
|
@@ -280,6 +281,7 @@ module Influxer
|
|
280
281
|
|
281
282
|
def get_points(list)
|
282
283
|
return list if normalized?
|
284
|
+
|
283
285
|
list.reduce([]) do |a, e|
|
284
286
|
a + e.fetch("values", []).map { |v| inject_tags(v, e["tags"] || {}) }
|
285
287
|
end
|
@@ -291,11 +293,13 @@ module Influxer
|
|
291
293
|
|
292
294
|
def method_missing(method, *args, &block)
|
293
295
|
return super unless @klass.respond_to?(method)
|
296
|
+
|
294
297
|
merge!(scoping { @klass.public_send(method, *args, &block) })
|
295
298
|
end
|
296
299
|
|
297
300
|
def respond_to_missing?(method, *args)
|
298
301
|
return true if @klass.respond_to?(method)
|
302
|
+
|
299
303
|
super
|
300
304
|
end
|
301
305
|
end
|
@@ -21,7 +21,7 @@ module Influxer
|
|
21
21
|
|
22
22
|
def percentile(name, val, alias_name = nil)
|
23
23
|
@values[:has_calculations] = true
|
24
|
-
select_values << "percentile(#{name}, #{val})#{alias_name ?
|
24
|
+
select_values << "percentile(#{name}, #{val})#{alias_name ? " as " + alias_name.to_s : ""}"
|
25
25
|
self
|
26
26
|
end
|
27
27
|
end
|
@@ -3,15 +3,15 @@
|
|
3
3
|
module Influxer
|
4
4
|
module TimeQuery #:nodoc:
|
5
5
|
TIME_ALIASES = {
|
6
|
-
hour:
|
7
|
-
minute:
|
8
|
-
second:
|
9
|
-
ms:
|
10
|
-
u:
|
11
|
-
week:
|
12
|
-
day:
|
13
|
-
month:
|
14
|
-
year:
|
6
|
+
hour: "1h",
|
7
|
+
minute: "1m",
|
8
|
+
second: "1s",
|
9
|
+
ms: "1ms",
|
10
|
+
u: "1u",
|
11
|
+
week: "1w",
|
12
|
+
day: "1d",
|
13
|
+
month: "30d",
|
14
|
+
year: "365d"
|
15
15
|
}.freeze
|
16
16
|
|
17
17
|
FILL_RESERVED = %i[null previous none].freeze
|
@@ -28,10 +28,10 @@ module Influxer
|
|
28
28
|
# # select * from metrics group by time(4d) fill(0)
|
29
29
|
def time(val, options = {})
|
30
30
|
@values[:time] = if val.is_a?(Symbol)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
TIME_ALIASES[val] || "1" + val.to_s
|
32
|
+
else
|
33
|
+
val
|
34
|
+
end
|
35
35
|
|
36
36
|
build_fill(options[:fill])
|
37
37
|
self
|
@@ -51,7 +51,7 @@ module Influxer
|
|
51
51
|
def past(val)
|
52
52
|
case val
|
53
53
|
when Symbol
|
54
|
-
where("time > now() - #{TIME_ALIASES[val] || (
|
54
|
+
where("time > now() - #{TIME_ALIASES[val] || ("1" + val.to_s)}")
|
55
55
|
when String
|
56
56
|
where("time > now() - #{val}")
|
57
57
|
else
|
@@ -76,6 +76,7 @@ module Influxer
|
|
76
76
|
|
77
77
|
def build_fill(val)
|
78
78
|
return if val.nil?
|
79
|
+
|
79
80
|
fill(FILL_RESERVED.include?(val) ? val.to_s : val.to_i)
|
80
81
|
end
|
81
82
|
end
|
@@ -29,6 +29,7 @@ module Influxer
|
|
29
29
|
|
30
30
|
def load
|
31
31
|
return if @null_relation
|
32
|
+
|
32
33
|
super
|
33
34
|
end
|
34
35
|
|
@@ -57,14 +58,15 @@ module Influxer
|
|
57
58
|
when NilClass
|
58
59
|
build_eql(key, /.*/, !negate)
|
59
60
|
when Regexp
|
60
|
-
"#{key}#{negate ?
|
61
|
+
"#{key}#{negate ? " !~ " : " =~ "}#{val.inspect}"
|
61
62
|
when Array
|
62
63
|
return build_none(negate) if val.empty?
|
64
|
+
|
63
65
|
build_in(key, val, negate)
|
64
66
|
when Range
|
65
67
|
build_range(key, val, negate)
|
66
68
|
else
|
67
|
-
"#{key}#{negate ?
|
69
|
+
"#{key}#{negate ? " <> " : " = "}#{quoted(val, key)}"
|
68
70
|
end
|
69
71
|
end
|
70
72
|
# rubocop:enable Metrics/CyclomaticComplexity
|
@@ -75,7 +77,7 @@ module Influxer
|
|
75
77
|
arr.each do |val|
|
76
78
|
buf << build_eql(key, val, negate)
|
77
79
|
end
|
78
|
-
buf.join(negate ?
|
80
|
+
buf.join(negate ? " and " : " or ").to_s
|
79
81
|
end
|
80
82
|
|
81
83
|
# rubocop: disable Metrics/AbcSize, Metrics/MethodLength, Style/IfInsideElse
|
@@ -100,7 +102,7 @@ module Influxer
|
|
100
102
|
|
101
103
|
def build_none(negate = false)
|
102
104
|
@null_relation = !negate
|
103
|
-
negate ?
|
105
|
+
negate ? "time >= 0" : "time < 0"
|
104
106
|
end
|
105
107
|
end
|
106
108
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "influxer/metrics/scoping/default"
|
4
|
+
require "influxer/metrics/scoping/named"
|
5
5
|
|
6
6
|
if Influxer.active_model3?
|
7
|
-
require
|
7
|
+
require "influxer/metrics/scoping/old_current_scope"
|
8
8
|
else
|
9
|
-
require
|
9
|
+
require "influxer/metrics/scoping/current_scope"
|
10
10
|
end
|
11
11
|
|
12
12
|
module Influxer
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "active_support/per_thread_registry"
|
4
4
|
|
5
5
|
module Influxer
|
6
6
|
module Scoping
|
@@ -39,6 +39,7 @@ module Influxer
|
|
39
39
|
|
40
40
|
def raise_invalid_scope_type!(scope_type)
|
41
41
|
return if VALID_SCOPE_TYPES.include?(scope_type)
|
42
|
+
|
42
43
|
raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. \
|
43
44
|
Scope types must be included in VALID_SCOPE_TYPES"
|
44
45
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "active_support/concern"
|
4
4
|
|
5
5
|
module Influxer
|
6
6
|
module Scoping
|
@@ -10,6 +10,7 @@ module Influxer
|
|
10
10
|
module ClassMethods
|
11
11
|
def scope(name, scope)
|
12
12
|
raise "Scope not defined: #{name}" if scope.nil? || !scope.respond_to?(:call)
|
13
|
+
|
13
14
|
singleton_class.send(:define_method, name) do |*args|
|
14
15
|
rel = all
|
15
16
|
rel.merge!(rel.scoping { scope.call(*args) })
|
data/lib/influxer/model.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "active_support"
|
4
4
|
|
5
5
|
module Influxer
|
6
6
|
# Add `has_metrics` method to AR::Base
|
@@ -8,9 +8,6 @@ module Influxer
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
module ClassMethods # :nodoc:
|
11
|
-
# rubocop:disable Naming/PredicateName
|
12
|
-
# rubocop:disable Metrics/MethodLength
|
13
|
-
# rubocop:disable Metrics/AbcSize
|
14
11
|
def has_metrics(*args, **params)
|
15
12
|
metrics_name = args.empty? ? "metrics" : args.first.to_s
|
16
13
|
|
@@ -22,12 +19,10 @@ module Influxer
|
|
22
19
|
foreign_key = params.fetch(:foreign_key, to_s.foreign_key)
|
23
20
|
|
24
21
|
define_method(metrics_name) do
|
25
|
-
rel_attrs = foreign_key ? {
|
22
|
+
rel_attrs = foreign_key ? {foreign_key => id} : {}
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
rel_attrs[key] = send(key)
|
30
|
-
end
|
24
|
+
attrs&.each do |key|
|
25
|
+
rel_attrs[key] = send(key)
|
31
26
|
end
|
32
27
|
Relation.new klass, attributes: rel_attrs
|
33
28
|
end
|
data/lib/influxer/version.rb
CHANGED
data/spec/cases/points_spec.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe DummyMetrics do
|
6
6
|
before do
|
7
7
|
stub_request(:get, "http://localhost:8086/query")
|
8
8
|
.with(
|
9
|
-
query: {
|
9
|
+
query: {q: 'select * from "dummy"', u: "root", p: "root", precision: "ns", db: "db"}
|
10
10
|
)
|
11
11
|
.to_return(body: fixture_file)
|
12
12
|
end
|
13
13
|
|
14
14
|
context "single_series" do
|
15
|
-
let(:fixture_file) { File.read(
|
15
|
+
let(:fixture_file) { File.read("./spec/fixtures/single_series.json") }
|
16
16
|
|
17
17
|
context "default format (values merged with tags)" do
|
18
18
|
subject { described_class.all.to_a }
|
@@ -25,7 +25,7 @@ describe DummyMetrics do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
context "empty result" do
|
28
|
-
let(:fixture_file) { File.read(
|
28
|
+
let(:fixture_file) { File.read("./spec/fixtures/empty_result.json") }
|
29
29
|
|
30
30
|
subject { described_class.all.to_a }
|
31
31
|
|