influxer 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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