influxer 1.1.4 → 1.2.2

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.
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