influxer 0.2.2 → 0.2.4

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.
@@ -3,13 +3,14 @@ require 'influxer/metrics/relation/fanout_query'
3
3
  require 'influxer/metrics/relation/calculations'
4
4
 
5
5
  module Influxer
6
+ # Relation is used to build queries
6
7
  class Relation
7
- attr_reader :values
8
-
9
8
  include Influxer::TimeQuery
10
9
  include Influxer::FanoutQuery
11
10
  include Influxer::Calculations
12
-
11
+
12
+ attr_reader :values
13
+
13
14
  MULTI_VALUE_METHODS = [:select, :where, :group]
14
15
 
15
16
  MULTI_KEY_METHODS = [:fanout]
@@ -62,40 +63,38 @@ module Influxer
62
63
  CODE
63
64
  end
64
65
 
65
-
66
- class << self
67
- # delegate array methods to to_a
68
- delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
69
- end
66
+ # delegate array methods to to_a
67
+ delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
68
+ to: :to_a
70
69
 
71
70
  # Initialize new Relation for 'klass' (Class) metrics.
72
- #
71
+ #
73
72
  # Available params:
74
- # :attributes - hash of attributes to be included to new Metrics object and where clause of Relation
75
- #
73
+ # :attributes - hash of attributes to be included to new Metrics object
74
+ # and where clause of Relation
75
+ #
76
76
  def initialize(klass, params = {})
77
77
  @klass = klass
78
78
  @instance = klass.new params[:attributes]
79
- self.reset
80
- self.where(params[:attributes]) if params[:attributes].present?
79
+ reset
80
+ where(params[:attributes]) if params[:attributes].present?
81
81
  self
82
82
  end
83
83
 
84
-
85
84
  def write(params = {})
86
85
  build params
87
86
  @instance.write
88
87
  end
89
88
 
90
89
  def build(params = {})
91
- params.each do |key,val|
90
+ params.each do |key, val|
92
91
  @instance.send("#{key}=", val) if @instance.respond_to?(key)
93
92
  end
94
93
  @instance
95
94
  end
96
95
 
97
96
  # accepts hash or strings conditions
98
- def where(*args,**hargs)
97
+ def where(*args, **hargs)
99
98
  build_where(args, hargs, false)
100
99
  self
101
100
  end
@@ -107,34 +106,24 @@ module Influxer
107
106
 
108
107
  def to_sql
109
108
  sql = ["select"]
109
+ select_values << "*" if select_values.empty?
110
110
 
111
- if select_values.empty?
112
- sql << "*"
113
- else
114
- sql << select_values.uniq.join(",")
115
- end
111
+ sql << select_values.uniq.join(",")
116
112
 
117
113
  sql << "from #{ build_series_name }"
114
+ sql << "merge #{ @klass.quoted_series(merge_value) }" unless merge_value.nil?
118
115
 
119
- unless merge_value.nil?
120
- sql << "merge #{ @instance.quote_series(merge_value) }"
121
- end
122
-
123
- unless group_values.empty? and time_value.nil?
124
- sql << "group by #{ (time_value.nil? ? [] : ['time('+@values[:time]+')']).concat(group_values).uniq.join(",") }"
116
+ unless group_values.empty? && time_value.nil?
117
+ group_fields = (time_value.nil? ? [] : ['time(' + @values[:time] + ')']) + group_values
118
+ group_fields.uniq!
119
+ sql << "group by #{ group_fields.join(',') }"
125
120
  end
126
121
 
127
- unless fill_value.nil?
128
- sql << "fill(#{ fill_value })"
129
- end
122
+ sql << "fill(#{ fill_value })" unless fill_value.nil?
130
123
 
131
- unless where_values.empty?
132
- sql << "where #{ where_values.join(" and ") }"
133
- end
124
+ sql << "where #{ where_values.join(' and ') }" unless where_values.empty?
134
125
 
135
- unless limit_value.nil?
136
- sql << "limit #{ limit_value }"
137
- end
126
+ sql << "limit #{ limit_value }" unless limit_value.nil?
138
127
  sql.join " "
139
128
  end
140
129
 
@@ -156,10 +145,10 @@ module Influxer
156
145
  select_values.clear
157
146
  limit(1).load
158
147
  end
159
- return @records.empty?
148
+ @records.empty?
160
149
  end
161
150
 
162
- def as_json(options=nil)
151
+ def as_json(options = nil)
163
152
  to_a.as_json(options)
164
153
  end
165
154
 
@@ -174,9 +163,7 @@ module Influxer
174
163
 
175
164
  sql << "from #{@instance.series}"
176
165
 
177
- unless where_values.empty?
178
- sql << "where #{where_values.join(" and ")}"
179
- end
166
+ sql << "where #{where_values.join(' and ')}" unless where_values.empty?
180
167
 
181
168
  sql = sql.join " "
182
169
 
@@ -193,11 +180,11 @@ module Influxer
193
180
  def merge!(rel)
194
181
  return self if rel.nil?
195
182
  MULTI_VALUE_METHODS.each do |method|
196
- (@values[method]||=[]).concat(rel.values[method]).uniq! unless rel.values[method].nil?
183
+ (@values[method] ||= []).concat(rel.values[method]).uniq! unless rel.values[method].nil?
197
184
  end
198
185
 
199
186
  MULTI_KEY_METHODS.each do |method|
200
- (@values[method]||={}).merge!(rel.values[method]) unless rel.values[method].nil?
187
+ (@values[method] ||= {}).merge!(rel.values[method]) unless rel.values[method].nil?
201
188
  end
202
189
 
203
190
  SINGLE_VALUE_METHODS.each do |method|
@@ -207,93 +194,93 @@ module Influxer
207
194
  self
208
195
  end
209
196
 
210
-
211
197
  protected
212
- def build_where(args, hargs, negate)
213
- case
214
- when (args.present? and args[0].is_a?(String))
215
- where_values.concat args.map{|str| "(#{str})"}
216
- when hargs.present?
217
- build_hash_where(hargs, negate)
218
- else
219
- false
220
- end
221
- end
222
198
 
223
- def build_hash_where(hargs, negate = false)
224
- hargs.each do |key, val|
225
- if @klass.fanout?(key)
226
- build_fanout(key,val)
227
- else
228
- where_values << "(#{ build_eql(key,val,negate) })"
229
- end
230
- end
199
+ def build_where(args, hargs, negate)
200
+ case
201
+ when (args.present? && args[0].is_a?(String))
202
+ where_values.concat args.map { |str| "(#{str})" }
203
+ when hargs.present?
204
+ build_hash_where(hargs, negate)
205
+ else
206
+ false
231
207
  end
208
+ end
232
209
 
233
- def build_eql(key,val,negate)
234
- case val
235
- when Regexp
236
- "#{key}#{ negate ? '!~' : '=~'}#{val.inspect}"
237
- when Array
238
- build_in(key,val,negate)
239
- when Range
240
- build_range(key,val,negate)
210
+ def build_hash_where(hargs, negate = false)
211
+ hargs.each do |key, val|
212
+ if @klass.fanout?(key)
213
+ build_fanout(key, val)
241
214
  else
242
- "#{key}#{ negate ? '<>' : '='}#{quoted(val)}"
243
- end
244
- end
245
-
246
- def build_in(key, arr, negate)
247
- buf = []
248
- arr.each do |val|
249
- buf << build_eql(key,val,negate)
215
+ where_values << "(#{ build_eql(key, val, negate) })"
250
216
  end
251
- "#{ buf.join( negate ? ' and ' : ' or ') }"
252
217
  end
218
+ end
253
219
 
254
- def build_range(key,val,negate)
255
- unless negate
256
- "#{key}>#{quoted(val.begin)} and #{key}<#{quoted(val.end)}"
257
- else
258
- "#{key}<#{quoted(val.begin)} and #{key}>#{quoted(val.end)}"
259
- end
220
+ def build_eql(key, val, negate)
221
+ case val
222
+ when Regexp
223
+ "#{key}#{ negate ? '!~' : '=~'}#{val.inspect}"
224
+ when Array
225
+ build_in(key, val, negate)
226
+ when Range
227
+ build_range(key, val, negate)
228
+ else
229
+ "#{key}#{ negate ? '<>' : '='}#{quoted(val)}"
260
230
  end
231
+ end
261
232
 
262
- def loaded?
263
- @loaded
233
+ def build_in(key, arr, negate)
234
+ buf = []
235
+ arr.each do |val|
236
+ buf << build_eql(key, val, negate)
264
237
  end
238
+ "#{ buf.join(negate ? ' and ' : ' or ') }"
239
+ end
265
240
 
266
- def reset
267
- @values = {}
268
- @records = nil
269
- @loaded = false
270
- self
241
+ def build_range(key, val, negate)
242
+ if negate
243
+ "#{key}<#{quoted(val.begin)} and #{key}>#{quoted(val.end)}"
244
+ else
245
+ "#{key}>#{quoted(val.begin)} and #{key}<#{quoted(val.end)}"
271
246
  end
247
+ end
272
248
 
273
- def reload
274
- self.reset
275
- self.load
276
- self
277
- end
249
+ def loaded?
250
+ @loaded
251
+ end
278
252
 
279
- def quoted(val)
280
- if val.is_a?(String) or val.is_a?(Symbol)
281
- "'#{val}'"
282
- elsif val.kind_of?(Time) or val.kind_of?(DateTime)
283
- "#{val.to_i}s"
284
- else
285
- val.to_s
286
- end
287
- end
253
+ def reset
254
+ @values = {}
255
+ @records = nil
256
+ @loaded = false
257
+ self
258
+ end
288
259
 
289
- def method_missing(method, *args, &block)
290
- if @klass.respond_to?(method)
291
- merge!(scoping { @klass.public_send(method, *args, &block) })
292
- end
293
- end
260
+ def reload
261
+ reset
262
+ load
263
+ self
264
+ end
294
265
 
295
- def get_points(hash)
296
- hash.values.reduce([],:+)
266
+ def quoted(val)
267
+ if val.is_a?(String) || val.is_a?(Symbol)
268
+ "'#{val}'"
269
+ elsif val.is_a?(Time) || val.is_a?(DateTime)
270
+ "#{val.to_i}s"
271
+ else
272
+ val.to_s
297
273
  end
274
+ end
275
+
276
+ def get_points(hash)
277
+ prepare_fanout_points(hash) if @values[:has_fanout] == true
278
+ hash.values.reduce([], :+)
279
+ end
280
+
281
+ def method_missing(method, *args, &block)
282
+ return super unless @klass.respond_to?(method)
283
+ merge!(scoping { @klass.public_send(method, *args, &block) })
284
+ end
298
285
  end
299
- end
286
+ end
@@ -1,6 +1,8 @@
1
+ require 'active_support/concern'
2
+
1
3
  module Influxer
2
4
  module Scoping
3
- module Default
5
+ module Default # :nodoc: all
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  included do
@@ -18,11 +20,11 @@ module Influxer
18
20
  end
19
21
 
20
22
  def default_scoped
21
- self.default_scopes.inject(Relation.new(self)) do |rel, scope|
22
- rel.merge!(rel.scoping{ scope.call })
23
+ self.default_scopes.inject(Relation.new(self)) do |rel, scope|
24
+ rel.merge!(rel.scoping { scope.call })
23
25
  end
24
26
  end
25
27
  end
26
28
  end
27
29
  end
28
- end
30
+ end
@@ -1,11 +1,13 @@
1
+ require 'active_support/concern'
2
+
1
3
  module Influxer
2
4
  module Scoping
3
- module Named
5
+ module Named # :nodoc: all
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  module ClassMethods
7
9
  def scope(name, scope)
8
- raise Error.new("Scope not defined: #{name}") if scope.nil? or !scope.respond_to?(:call)
10
+ fail "Scope not defined: #{name}" if scope.nil? || !scope.respond_to?(:call)
9
11
  singleton_class.send(:define_method, name) do |*args|
10
12
  rel = all
11
13
  rel.merge!(rel.scoping { scope.call(*args) })
@@ -15,4 +17,4 @@ module Influxer
15
17
  end
16
18
  end
17
19
  end
18
- end
20
+ end
@@ -3,22 +3,22 @@ require 'influxer/metrics/scoping/default'
3
3
  require 'influxer/metrics/scoping/named'
4
4
 
5
5
  module Influxer
6
- module Scoping
6
+ module Scoping # :nodoc:
7
7
  extend ActiveSupport::Concern
8
8
 
9
- class Error < StandardError; end;
9
+ class Error < StandardError; end
10
10
 
11
11
  included do
12
12
  include Default
13
13
  include Named
14
14
  end
15
15
 
16
- module ClassMethods
17
- def current_scope #:nodoc:
16
+ module ClassMethods # :nodoc:
17
+ def current_scope
18
18
  ScopeRegistry.value_for(:current_scope, name)
19
19
  end
20
20
 
21
- def current_scope=(scope) #:nodoc:
21
+ def current_scope=(scope)
22
22
  ScopeRegistry.set_value_for(:current_scope, name, scope)
23
23
  end
24
24
  end
@@ -48,9 +48,10 @@ module Influxer
48
48
 
49
49
  def raise_invalid_scope_type!(scope_type)
50
50
  if !VALID_SCOPE_TYPES.include?(scope_type)
51
- raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
51
+ raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. \
52
+ Scope types must be included in VALID_SCOPE_TYPES"
52
53
  end
53
54
  end
54
55
  end
55
56
  end
56
- end
57
+ end
@@ -1,35 +1,34 @@
1
1
  require 'active_support'
2
2
 
3
3
  module Influxer
4
+ # Add `has_metrics` method to AR::Base
4
5
  module Model
5
6
  extend ActiveSupport::Concern
6
-
7
- module ClassMethods
7
+
8
+ module ClassMethods # :nodoc:
8
9
  def has_metrics(*args, **params)
9
10
  metrics_name = args.empty? ? "metrics" : args.first.to_s
10
11
 
11
- klass = params[:class_name].present? ? params[:class_name] : "#{self}Metrics"
12
+ klass = params[:class_name].present? ? params[:class_name] : "#{self}Metrics"
12
13
  klass = klass.constantize
13
14
 
14
15
  attrs = nil
15
16
 
16
- if params[:inherits].present?
17
- attrs = params[:inherits]
18
- end
17
+ attrs = params[:inherits] if params[:inherits].present?
19
18
 
20
- _foreign_key = params.key?(:foreign_key) ? params[:foreign_key] : self.to_s.foreign_key
19
+ foreign_key = params.key?(:foreign_key) ? params[:foreign_key] : to_s.foreign_key
21
20
 
22
21
  define_method(metrics_name) do
23
- rel_attrs = _foreign_key ? {_foreign_key => self.id} : {}
24
-
22
+ rel_attrs = foreign_key ? { foreign_key => id } : {}
23
+
25
24
  unless attrs.nil?
26
25
  attrs.each do |key|
27
- rel_attrs[key] = self.send(key)
28
- end
26
+ rel_attrs[key] = send(key)
27
+ end
29
28
  end
30
29
  Relation.new klass, attributes: rel_attrs
31
30
  end
32
31
  end
33
32
  end
34
33
  end
35
- end
34
+ end
@@ -1,3 +1,3 @@
1
- module Influxer
2
- VERSION = "0.2.2"
1
+ module Influxer # :nodoc:
2
+ VERSION = "0.2.4"
3
3
  end
data/lib/influxer.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'influxer/version'
2
2
 
3
+ # Rails client for InfluxDB
3
4
  module Influxer
4
5
  require 'influxer/config'
5
6
  require 'influxer/client'
6
7
  require 'influxer/metrics/metrics'
7
8
 
8
- module Model
9
+ module Model # :nodoc:
9
10
  require 'influxer/model'
10
11
  end
11
12
 
data/spec/client_spec.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Influxer::Client do
4
-
5
4
  after(:each) do
6
5
  Rails.cache.clear
7
6
  end
@@ -17,7 +16,7 @@ describe Influxer::Client do
17
16
 
18
17
  describe "cache" do
19
18
  before do
20
- allow_any_instance_of(Influxer::Client).to receive(:query) do |_, sql|
19
+ allow_any_instance_of(Influxer::Client).to receive(:query) do |_, sql|
21
20
  sql
22
21
  end
23
22
  end
@@ -36,13 +35,13 @@ describe Influxer::Client do
36
35
  end
37
36
 
38
37
  it "should write data to cache with expiration" do
39
- conf.cache = {expires_in: 1}
38
+ conf.cache = { expires_in: 1 }
40
39
 
41
40
  client.cached_query(q)
42
41
  expect(Rails.cache.exist?("influxer:listseries")).to be_truthy
43
-
42
+
44
43
  sleep 2
45
44
  expect(Rails.cache.exist?("influxer:listseries")).to be_falsey
46
45
  end
47
46
  end
48
- end
47
+ end
data/spec/config_spec.rb CHANGED
@@ -1,18 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Influxer::Config do
4
-
5
4
  let(:conf) { Influxer.config }
6
5
 
7
6
  it "should load config from file" do
8
7
  expect(conf.retry).to eq 5
9
- expect(conf.host).to eq "test.host"
8
+ expect(conf.host).to eq "test.host"
10
9
  end
11
10
 
12
11
  unless Rails.application.try(:secrets).nil?
13
12
  it "should load config from secrets" do
14
13
  expect(conf.username).to eq "test"
15
- expect(conf.password).to eq "test"
14
+ expect(conf.password).to eq "test"
16
15
  end
17
16
  end
18
17
  end
@@ -1,3 +1,3 @@
1
1
  class TestoMetrics < Influxer::Metrics
2
2
  attributes :testo_id, :receipt_id, :testo
3
- end
3
+ end
@@ -3,4 +3,4 @@ class Testo < ActiveRecord::Base
3
3
  has_metrics :testo_metrics, class_name: "TestoMetrics", inherits: [:receipt_id]
4
4
  has_metrics :testo2_metrics, class_name: "TestoMetrics", foreign_key: :testo
5
5
  has_metrics :custom_metrics, class_name: "TestoMetrics", foreign_key: nil
6
- end
6
+ end
@@ -21,4 +21,3 @@ module Dummy
21
21
  # config.i18n.default_locale = :de
22
22
  end
23
23
  end
24
-
@@ -1,3 +1,3 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
- Dummy::Application.config.action_dispatch.cookies_serializer = :json
3
+ Dummy::Application.config.action_dispatch.cookies_serializer = :json
@@ -0,0 +1,23 @@
1
+ {
2
+ "dummy_by_day_user_6":
3
+ [
4
+ {
5
+ "time": 1430092800,
6
+ "sequence_number": 1,
7
+ "time_spent": 100
8
+ }
9
+ ],
10
+ "dummy_by_day_user_2":
11
+ [
12
+ {
13
+ "time": 1430092800,
14
+ "sequence_number": 1,
15
+ "time_spent": 50
16
+ },
17
+ {
18
+ "time": 1430094800,
19
+ "sequence_number": 2,
20
+ "time_spent": 150
21
+ }
22
+ ]
23
+ }
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Influxer::Metrics do
4
4
  before do
5
- allow_any_instance_of(Influxer::Client).to receive(:query) do |_, sql|
5
+ allow_any_instance_of(Influxer::Client).to receive(:query) do |_, sql|
6
6
  sql
7
7
  end
8
8
  end
@@ -40,7 +40,22 @@ describe Influxer::Metrics do
40
40
  end
41
41
 
42
42
  it "should work with regexp fanouts" do
43
- expect(dappy.where(dummy_id: 100).by_user(/[1-3]/).daily.to_sql).to eq "select * from merge(/^dummy_by_day_user_[1-3]$/) where (dummy_id=100)"
43
+ expect(dappy.where(dummy_id: 100).by_user(/[1-3]/).daily.to_sql)
44
+ .to eq "select * from /^dummy_by_day_user_[1-3]$/ where (dummy_id=100)"
44
45
  end
45
46
  end
46
- end
47
+
48
+ describe "#prepare_fanout_points" do
49
+ before do
50
+ allow_any_instance_of(Influxer::Client).to receive(:query) do |_, _sql|
51
+ JSON.parse(File.read('./spec/fixtures/fanout_series.json'))
52
+ end
53
+ end
54
+
55
+ it "sets fanout fields values" do
56
+ res = dappy.by_user(/\d+/).daily.to_a
57
+ expect(res.detect { |v| v["user"] == '6' }).to include('time_spent' => 100, 'by' => 'day')
58
+ expect(res.select { |v| v["user"] == '2' }.size).to eq 2
59
+ end
60
+ end
61
+ end