influxer 1.1.4 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +98 -0
  3. data/{MIT-LICENSE → LICENSE.txt} +1 -1
  4. data/README.md +106 -47
  5. data/lib/influxer.rb +10 -9
  6. data/lib/influxer/client.rb +1 -1
  7. data/lib/influxer/config.rb +19 -6
  8. data/lib/influxer/engine.rb +1 -1
  9. data/lib/influxer/metrics/active_model3/model.rb +2 -4
  10. data/lib/influxer/metrics/metrics.rb +10 -13
  11. data/lib/influxer/metrics/quoting/timestamp.rb +23 -11
  12. data/lib/influxer/metrics/relation.rb +33 -17
  13. data/lib/influxer/metrics/relation/calculations.rb +1 -1
  14. data/lib/influxer/metrics/relation/time_query.rb +15 -13
  15. data/lib/influxer/metrics/relation/where_clause.rb +19 -11
  16. data/lib/influxer/metrics/scoping.rb +4 -4
  17. data/lib/influxer/metrics/scoping/current_scope.rb +2 -1
  18. data/lib/influxer/metrics/scoping/default.rb +1 -1
  19. data/lib/influxer/metrics/scoping/named.rb +2 -1
  20. data/lib/influxer/model.rb +4 -9
  21. data/lib/influxer/rails/client.rb +6 -6
  22. data/lib/influxer/version.rb +1 -1
  23. metadata +30 -95
  24. data/.gitignore +0 -37
  25. data/.rspec +0 -2
  26. data/.rubocop.yml +0 -77
  27. data/.travis.yml +0 -10
  28. data/Changelog.md +0 -111
  29. data/Gemfile +0 -10
  30. data/Rakefile +0 -13
  31. data/gemfiles/rails32.gemfile +0 -7
  32. data/gemfiles/rails42.gemfile +0 -7
  33. data/gemfiles/rails5.gemfile +0 -7
  34. data/influxer.gemspec +0 -33
  35. data/spec/cases/points_spec.rb +0 -36
  36. data/spec/cases/write_points_spec.rb +0 -85
  37. data/spec/client_spec.rb +0 -46
  38. data/spec/fixtures/empty_result.json +0 -21
  39. data/spec/fixtures/single_series.json +0 -29
  40. data/spec/metrics/metrics_spec.rb +0 -283
  41. data/spec/metrics/relation_spec.rb +0 -477
  42. data/spec/metrics/scoping_spec.rb +0 -66
  43. data/spec/model/user_spec.rb +0 -46
  44. data/spec/spec_helper.rb +0 -64
  45. data/spec/support/metrics/action_metrics.rb +0 -5
  46. data/spec/support/metrics/custom_metrics.rb +0 -6
  47. data/spec/support/metrics/dummy_metrics.rb +0 -12
  48. data/spec/support/metrics/user_metrics.rb +0 -6
  49. data/spec/support/metrics/visits_metrics.rb +0 -8
  50. data/spec/support/shared_contexts/shared_query.rb +0 -16
  51. data/spec/support/user.rb +0 -16
@@ -3,27 +3,27 @@
3
3
  module Influxer
4
4
  module TimestampQuoting #:nodoc:
5
5
  TIME_FACTORS = {
6
- 'ns' => 1_000_000_000,
7
- 'ms' => 1_000,
8
- 's' => 1
6
+ "ns" => 1_000_000_000,
7
+ "ms" => 1_000,
8
+ "s" => 1
9
9
  }.freeze
10
10
 
11
- DEFAULT_PRECISION = 'ns'
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.keys.include?(client.time_precision)
18
- client.time_precision
19
- else
20
- DEFAULT_PRECISION
21
- end
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.keys.include?(client.time_precision) &&
26
- !val.is_a?(Numeric)
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. " \
@@ -40,6 +40,18 @@ module Influxer
40
40
  "#{factorize_timestamp(val, TIME_FACTORS.fetch(precision))}#{precision}"
41
41
  end
42
42
 
43
+ def quote_timestamp_for_write(val, client)
44
+ if !TIME_FACTORS.key?(client.time_precision) &&
45
+ !val.is_a?(Numeric)
46
+ raise ArgumentError,
47
+ "Influxer doesn't support quoting #{val} " \
48
+ " with '#{client.time_precision}' precision. " \
49
+ "Please, convert to numeric value yourself"
50
+ end
51
+
52
+ factorize_timestamp(val, TIME_FACTORS.fetch(client.time_precision))
53
+ end
54
+
43
55
  def factorize_timestamp(val, factor)
44
56
  case val
45
57
  when Numeric
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
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'
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
@@ -23,11 +22,11 @@ module Influxer
23
22
 
24
23
  MULTI_KEY_METHODS = %i[fanout].freeze
25
24
 
26
- SINGLE_VALUE_METHODS = %i[fill time limit offset slimit soffset from normalized].freeze
25
+ SINGLE_VALUE_METHODS = %i[fill time limit offset slimit soffset from normalized timezone].freeze
27
26
 
28
27
  MULTI_VALUE_SIMPLE_METHODS = %i[select group].freeze
29
28
 
30
- SINGLE_VALUE_SIMPLE_METHODS = %i[fill limit offset slimit soffset from].freeze
29
+ SINGLE_VALUE_SIMPLE_METHODS = %i[fill limit offset slimit soffset from timezone].freeze
31
30
 
32
31
  MULTI_VALUE_METHODS.each do |name|
33
32
  class_eval <<-CODE, __FILE__, __LINE__ + 1
@@ -122,6 +121,13 @@ module Influxer
122
121
  self
123
122
  end
124
123
 
124
+ def timezone(val)
125
+ return self if val.blank?
126
+
127
+ @values[:timezone] = val
128
+ self
129
+ end
130
+
125
131
  def order(val)
126
132
  case val
127
133
  when Hash
@@ -144,22 +150,23 @@ module Influxer
144
150
 
145
151
  sql << "from #{build_series_name}"
146
152
 
147
- sql << "where #{where_values.join(' and ')}" unless where_values.empty?
153
+ sql << "where #{where_values.join(" and ")}" unless where_values.empty?
148
154
 
149
155
  unless group_values.empty? && time_value.nil?
150
- group_fields = (time_value.nil? ? [] : ['time(' + @values[:time] + ')']) + group_values
156
+ group_fields = (time_value.nil? ? [] : ["time(" + @values[:time] + ")"]) + group_values
151
157
  group_fields.uniq!
152
- sql << "group by #{group_fields.join(', ')}"
158
+ sql << "group by #{group_fields.join(", ")}"
153
159
  end
154
160
 
155
161
  sql << "fill(#{fill_value})" unless fill_value.nil?
156
162
 
157
- sql << "order by #{order_values.uniq.join(',')}" unless order_values.empty?
163
+ sql << "order by #{order_values.uniq.join(",")}" unless order_values.empty?
158
164
 
159
165
  sql << "limit #{limit_value}" unless limit_value.nil?
160
166
  sql << "offset #{offset_value}" unless offset_value.nil?
161
167
  sql << "slimit #{slimit_value}" unless slimit_value.nil?
162
168
  sql << "soffset #{soffset_value}" unless soffset_value.nil?
169
+ sql << "TZ('#{timezone_value}')" unless timezone_value.blank?
163
170
  sql.join " "
164
171
  end
165
172
  # rubocop:enable Metrics/AbcSize
@@ -169,14 +176,15 @@ module Influxer
169
176
 
170
177
  def to_a
171
178
  return @records if loaded?
179
+
172
180
  load
173
181
  end
174
182
 
175
183
  def inspect
176
184
  entries = to_a.take(11).map!(&:inspect)
177
- entries[10] = '...' if entries.size == 11
185
+ entries[10] = "..." if entries.size == 11
178
186
 
179
- "#<#{self.class.name} [#{entries.join(', ')}]>"
187
+ "#<#{self.class.name} [#{entries.join(", ")}]>"
180
188
  end
181
189
 
182
190
  def empty?
@@ -205,11 +213,15 @@ module Influxer
205
213
  end
206
214
 
207
215
  def delete_all
208
- sql = ["drop series"]
216
+ sql = if where_contains_time?
217
+ ["delete"]
218
+ else
219
+ ["drop series"]
220
+ end
209
221
 
210
- sql << "from #{@instance.series}"
222
+ sql << "from #{@instance.series(write: true)}"
211
223
 
212
- sql << "where #{where_values.join(' and ')}" unless where_values.empty?
224
+ sql << "where #{where_values.join(" and ")}" unless where_values.empty?
213
225
 
214
226
  sql = sql.join " "
215
227
 
@@ -228,6 +240,7 @@ module Influxer
228
240
  # rubocop:disable Metrics/MethodLength
229
241
  def merge!(rel)
230
242
  return self if rel.nil?
243
+
231
244
  MULTI_VALUE_METHODS.each do |method|
232
245
  (@values[method] ||= []).concat(rel.values[method]).uniq! unless rel.values[method].nil?
233
246
  end
@@ -280,6 +293,7 @@ module Influxer
280
293
 
281
294
  def get_points(list)
282
295
  return list if normalized?
296
+
283
297
  list.reduce([]) do |a, e|
284
298
  a + e.fetch("values", []).map { |v| inject_tags(v, e["tags"] || {}) }
285
299
  end
@@ -291,11 +305,13 @@ module Influxer
291
305
 
292
306
  def method_missing(method, *args, &block)
293
307
  return super unless @klass.respond_to?(method)
308
+
294
309
  merge!(scoping { @klass.public_send(method, *args, &block) })
295
310
  end
296
311
 
297
312
  def respond_to_missing?(method, *args)
298
313
  return true if @klass.respond_to?(method)
314
+
299
315
  super
300
316
  end
301
317
  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 ? ' as ' + alias_name.to_s : ''}"
24
+ select_values << "percentile(#{name}, #{val})#{alias_name ? " as " + alias_name.to_s : ""}"
25
25
  self
26
26
  end
27
27
  end
@@ -3,14 +3,15 @@
3
3
  module Influxer
4
4
  module TimeQuery #:nodoc:
5
5
  TIME_ALIASES = {
6
- hour: '1h',
7
- minute: '1m',
8
- second: '1s',
9
- ms: '1ms',
10
- u: '1u',
11
- week: '1w',
12
- day: '1d',
13
- month: '30d'
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"
14
15
  }.freeze
15
16
 
16
17
  FILL_RESERVED = %i[null previous none].freeze
@@ -27,10 +28,10 @@ module Influxer
27
28
  # # select * from metrics group by time(4d) fill(0)
28
29
  def time(val, options = {})
29
30
  @values[:time] = if val.is_a?(Symbol)
30
- TIME_ALIASES[val] || '1' + val.to_s
31
- else
32
- val
33
- end
31
+ TIME_ALIASES[val] || "1" + val.to_s
32
+ else
33
+ val
34
+ end
34
35
 
35
36
  build_fill(options[:fill])
36
37
  self
@@ -50,7 +51,7 @@ module Influxer
50
51
  def past(val)
51
52
  case val
52
53
  when Symbol
53
- where("time > now() - #{TIME_ALIASES[val] || ('1' + val.to_s)}")
54
+ where("time > now() - #{TIME_ALIASES[val] || ("1" + val.to_s)}")
54
55
  when String
55
56
  where("time > now() - #{val}")
56
57
  else
@@ -75,6 +76,7 @@ module Influxer
75
76
 
76
77
  def build_fill(val)
77
78
  return if val.nil?
79
+
78
80
  fill(FILL_RESERVED.include?(val) ? val.to_s : val.to_i)
79
81
  end
80
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 ? ' !~ ' : ' =~ '}#{val.inspect}"
61
+ "#{key}#{negate ? " !~ " : " =~ "}#{val.inspect}"
61
62
  when Array
62
- return build_none if val.empty?
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 ? ' <> ' : ' = '}#{quoted(val, key)}"
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 ? ' and ' : ' or ').to_s
80
+ buf.join(negate ? " and " : " or ").to_s
79
81
  end
80
82
 
81
83
  # rubocop: disable Metrics/AbcSize, Metrics/MethodLength, Style/IfInsideElse
@@ -83,24 +85,30 @@ module Influxer
83
85
  if val.exclude_end?
84
86
  # begin...end range
85
87
  if negate
86
- "#{key} < #{quoted(val.begin)} or #{key} >= #{quoted(val.end)}"
88
+ "#{key} < #{quoted(val.begin, key)} or #{key} >= #{quoted(val.end, key)}"
87
89
  else
88
- "#{key} >= #{quoted(val.begin)} and #{key} < #{quoted(val.end)}"
90
+ "#{key} >= #{quoted(val.begin, key)} and #{key} < #{quoted(val.end, key)}"
89
91
  end
90
92
  else
91
93
  # begin..end range
92
94
  if negate
93
- "#{key} < #{quoted(val.begin)} or #{key} > #{quoted(val.end)}"
95
+ "#{key} < #{quoted(val.begin, key)} or #{key} > #{quoted(val.end, key)}"
94
96
  else
95
- "#{key} >= #{quoted(val.begin)} and #{key} <= #{quoted(val.end)}"
97
+ "#{key} >= #{quoted(val.begin, key)} and #{key} <= #{quoted(val.end, key)}"
96
98
  end
97
99
  end
98
100
  end
99
101
  # rubocop: enable Metrics/AbcSize, Metrics/MethodLength, Style/IfInsideElse
100
102
 
101
- def build_none
102
- @null_relation = true
103
- build_eql(1, 0, false)
103
+ def build_none(negate = false)
104
+ @null_relation = !negate
105
+ negate ? "time >= 0" : "time < 0"
106
+ end
107
+
108
+ def where_contains_time?
109
+ where_values.any? do |where_clause|
110
+ /time( )/ === where_clause
111
+ end
104
112
  end
105
113
  end
106
114
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'influxer/metrics/scoping/default'
4
- require 'influxer/metrics/scoping/named'
3
+ require "influxer/metrics/scoping/default"
4
+ require "influxer/metrics/scoping/named"
5
5
 
6
6
  if Influxer.active_model3?
7
- require 'influxer/metrics/scoping/old_current_scope'
7
+ require "influxer/metrics/scoping/old_current_scope"
8
8
  else
9
- require 'influxer/metrics/scoping/current_scope'
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 'active_support/per_thread_registry'
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 'active_support/concern'
3
+ require "active_support/concern"
4
4
 
5
5
  module Influxer
6
6
  module Scoping
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
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) })
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support'
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 ? { foreign_key => id } : {}
22
+ rel_attrs = foreign_key ? {foreign_key => id} : {}
26
23
 
27
- unless attrs.nil?
28
- attrs.each do |key|
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
@@ -6,10 +6,10 @@ module Influxer
6
6
  class Client
7
7
  def query(sql, options = {})
8
8
  log_sql(sql) do
9
- if !options.fetch(:cache, true) || Influxer.config.cache == false
10
- super(sql, options)
9
+ if !(options.fetch(:cache, true) && Influxer.config.cache_enabled)
10
+ super(sql, **options)
11
11
  else
12
- Rails.cache.fetch(normalized_cache_key(sql), cache_options(sql)) { super(sql, options) }
12
+ Rails.cache.fetch(normalized_cache_key(sql), **cache_options(sql)) { super(sql, **options) }
13
13
  end
14
14
  end
15
15
  end
@@ -33,13 +33,13 @@ module Influxer
33
33
  # of config.cache if defined
34
34
  def cache_options(sql = nil)
35
35
  options = Influxer.config.cache.dup
36
- options[:expires_in] = (options[:cache_now_for] || 60) if sql =~ /\snow\(\)/
37
- options
36
+ options[:expires_in] = (options[:cache_now_for] || 60) if /\snow\(\)/.match?(sql)
37
+ options.symbolize_keys
38
38
  end
39
39
 
40
40
  # add prefix; remove whitespaces
41
41
  def normalized_cache_key(sql)
42
- "influxer:#{sql.gsub(/\s*/, '')}"
42
+ "influxer:#{sql.gsub(/\s*/, "")}"
43
43
  end
44
44
 
45
45
  def logger