ruby-druid 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: adfe39dfd535cfb911d89bece7d3921b8e63c162
4
- data.tar.gz: 74fcfe3637e3131dfb9e057c3ee1c33ff62840bf
3
+ metadata.gz: d0e676ac15efc4d9777fa182d8c8855bc1ebf386
4
+ data.tar.gz: e54d2ec80e3bb5efdf02d3b5b127c565c5cfce86
5
5
  SHA512:
6
- metadata.gz: d06463d4a10c5d142f09b71acb3785bf8906cf5cf1719995b60006499754d609fce7ba1ed9b23ea338dd1587bb6b6bc967509c696ba2c09fc80e1a67367b529f
7
- data.tar.gz: a6726f41601627488627aeeedc55163b2e65602d3845dacf0a1bcb66ec412d7dca8333cdeb440a860046ac75a93447132cd0ed5d250d5094532ae50743cda7d9
6
+ metadata.gz: 884a621b0fb481490d114248bfff0207bc2fd54e889832cf86318c6d26fb53c73c535d97d4d832fc9872a4f6b76b0d426a7050190e41639abfad2d728a36dd7a
7
+ data.tar.gz: b46976c63af7169c6581d092522f5ac97098320efe903bd6d5a6e58c9c2792aab34d0e17c474de174fc44e74d91a0fc6594a89d39beaf3c8f7fabe3f432af21e
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --require spec_helper
data/.travis.yml CHANGED
@@ -3,8 +3,7 @@ rvm:
3
3
  - jruby
4
4
  - 2.0.0
5
5
  - 1.9.3
6
+ script:
7
+ - bundle exec rspec --format documentation
6
8
  notifications:
7
9
  email: false
8
- hipchat:
9
- rooms:
10
- secure: WhPGqnsNAVchiJz/rmmIPIFHXI7NVd+k/zClVhtgyoPEdebFYFgOCEIGbE/53IVymVeXFFBeJUVQg1Um4AVsZzVpS5sC6ABWw7rH5PZQZ7k177ZmuhbIAVYLLXcX0OmolgsATvGejifVj5i/Kld46kRx3JDlWL/mA465Kso7a/k=
data/README.md CHANGED
@@ -91,12 +91,18 @@ A simple syntax for post aggregations with +,-,/,* can be used like:
91
91
 
92
92
  ```ruby
93
93
  query = Druid::Query.new('service/source').long_sum([:aggregate1, :aggregate2])
94
- query.postagg{(aggregate2 + aggregate2).as output_field_name}
94
+ query.postagg { (aggregate2 + aggregate2).as output_field_name }
95
95
  ```
96
96
 
97
97
  Required fields for the postaggregation are fetched automatically by the
98
98
  library.
99
99
 
100
+ Javascript post aggregations are also supported:
101
+
102
+ ```ruby
103
+ query.postagg { js('function(aggregate1, aggregate2) { return aggregate1 + aggregate2; }').as result }
104
+ ```
105
+
100
106
  ### Query Interval
101
107
 
102
108
  The interval for the query takes a string with date and time or objects that
data/lib/druid/having.rb CHANGED
@@ -7,13 +7,19 @@ module Druid
7
7
  end
8
8
  end
9
9
 
10
- class HavingClause
11
- (instance_methods + private_instance_methods).each do |method|
12
- unless method.to_s =~ /^(__|instance_eval|instance_exec|initialize|object_id|raise|puts|inspect|class)/ || method.to_s =~ /\?/
13
- undef_method method
14
- end
10
+ class HavingFilter
11
+ include Serializable
12
+
13
+ def clause?
14
+ is_a?(HavingClause)
15
+ end
16
+
17
+ def operator?
18
+ is_a?(HavingOperator)
15
19
  end
20
+ end
16
21
 
22
+ class HavingClause < HavingFilter
17
23
  def initialize(metric)
18
24
  @metric = metric
19
25
  end
@@ -30,24 +36,34 @@ module Druid
30
36
  self
31
37
  end
32
38
 
33
- def to_s
34
- to_hash.to_s
39
+ def to_hash
40
+ {
41
+ :type => @type,
42
+ :aggregation => @metric,
43
+ :value => @value
44
+ }
45
+ end
46
+ end
47
+
48
+ class HavingOperator < HavingFilter
49
+ def initialize(type)
50
+ @type = type
51
+ @elements = []
35
52
  end
36
53
 
37
- def as_json(*a)
38
- to_hash
54
+ def and?
55
+ @type == 'and'
39
56
  end
40
57
 
41
- def to_json(*a)
42
- to_hash.to_json(*a)
58
+ def add(element)
59
+ @elements << element
43
60
  end
44
61
 
45
62
  def to_hash
46
63
  {
47
64
  :type => @type,
48
- :aggregation => @metric,
49
- :value => @value
65
+ :havingSpecs => @elements
50
66
  }
51
67
  end
52
68
  end
53
- end
69
+ end
@@ -5,6 +5,14 @@ module Druid
5
5
  PostAggregationField.new(name)
6
6
  end
7
7
  end
8
+
9
+ def js(*args)
10
+ if args.empty?
11
+ PostAggregationField.new(:js)
12
+ else
13
+ PostAggregationJavascript.new(args.first)
14
+ end
15
+ end
8
16
  end
9
17
 
10
18
  module PostAggregationOperators
@@ -90,6 +98,8 @@ module Druid
90
98
  end
91
99
 
92
100
  class PostAggregationConstant
101
+ include PostAggregationOperators
102
+
93
103
  attr_reader :value
94
104
 
95
105
  def initialize(value)
@@ -108,4 +118,40 @@ module Druid
108
118
  to_hash
109
119
  end
110
120
  end
121
+
122
+ class PostAggregationJavascript
123
+ include PostAggregationOperators
124
+ include Serializable
125
+
126
+ def initialize(function)
127
+ @field_names = extract_fields(function)
128
+ @function = function
129
+ end
130
+
131
+ def get_field_names
132
+ @field_names
133
+ end
134
+
135
+ def as(field)
136
+ @name = field.name.to_s
137
+ self
138
+ end
139
+
140
+ def to_hash
141
+ {
142
+ "type" => "javascript",
143
+ "name" => @name,
144
+ "fieldNames" => @field_names,
145
+ "function" => @function
146
+ }
147
+ end
148
+
149
+ private
150
+
151
+ def extract_fields(function)
152
+ match = function.match(/function\((.+)\)/)
153
+ raise 'Invalid Javascript function' unless match && match.captures
154
+ match.captures.first.split(',').map {|field| field.strip }
155
+ end
156
+ end
111
157
  end
data/lib/druid/query.rb CHANGED
@@ -1,6 +1,8 @@
1
+ require 'druid/serializable'
1
2
  require 'druid/filter'
2
3
  require 'druid/having'
3
4
  require 'druid/post_aggregation'
5
+
4
6
  require 'time'
5
7
  require 'json'
6
8
 
@@ -137,7 +139,20 @@ module Druid
137
139
 
138
140
  def having(&block)
139
141
  having = Having.new.instance_exec(&block)
140
- @properties[:having] = having
142
+
143
+ if old_having = @properties[:having]
144
+ if old_having.operator? && old_having.and?
145
+ new_having = old_having
146
+ else
147
+ new_having = HavingOperator.new('and')
148
+ new_having.add(old_having)
149
+ end
150
+ new_having.add(having)
151
+ else
152
+ new_having = having
153
+ end
154
+
155
+ @properties[:having] = new_having
141
156
  self
142
157
  end
143
158
 
@@ -0,0 +1,19 @@
1
+ module Druid
2
+ module Serializable
3
+ def to_hash
4
+ {}
5
+ end
6
+
7
+ def to_s
8
+ to_hash.to_s
9
+ end
10
+
11
+ def as_json(*a)
12
+ to_hash
13
+ end
14
+
15
+ def to_json(*a)
16
+ to_hash.to_json(*a)
17
+ end
18
+ end
19
+ end
data/ruby-druid.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "ruby-druid"
5
- spec.version = "0.1.8"
5
+ spec.version = "0.1.9"
6
6
  spec.authors = ["LiquidM, Inc."]
7
7
  spec.email = ["opensource@liquidm.com"]
8
8
  spec.summary = %q{Ruby client for metamx druid}
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe Druid::Client do
4
2
 
5
3
  it 'calls zookeeper on intialize' do
@@ -1,5 +1,3 @@
1
- require "spec_helper"
2
-
3
1
  describe Druid::Query do
4
2
 
5
3
  before :each do
@@ -20,7 +18,7 @@ describe Druid::Query do
20
18
  @query.group_by()
21
19
  JSON.parse(@query.to_json)['queryType'].should == 'groupBy'
22
20
  end
23
-
21
+
24
22
  it 'sets query type to timeseries' do
25
23
  @query.time_series()
26
24
  JSON.parse(@query.to_json)['queryType'].should == 'timeseries'
@@ -39,91 +37,113 @@ describe Druid::Query do
39
37
  result['threshold'].should == 25
40
38
  end
41
39
 
42
- it 'build a post aggregation with a constant right' do
43
- @query.postagg{(a + 1).as ctr }
40
+ describe '#postagg' do
41
+ it 'build a post aggregation with a constant right' do
42
+ @query.postagg{(a + 1).as ctr }
44
43
 
45
- JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
46
- "fn"=>"+",
47
- "fields"=>
48
- [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
49
- {"type"=>"constant", "value"=>1}],
50
- "name"=>"ctr"}]
51
- end
44
+ JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
45
+ "fn"=>"+",
46
+ "fields"=>
47
+ [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
48
+ {"type"=>"constant", "value"=>1}],
49
+ "name"=>"ctr"}]
50
+ end
52
51
 
53
- it 'build a + post aggregation' do
54
- @query.postagg{(a + b).as ctr }
55
- JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
56
- "fn"=>"+",
57
- "fields"=>
58
- [{"type"=>"fieldAccess","name"=>"a", "fieldName"=>"a"},
59
- {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
60
- "name"=>"ctr"}]
61
- end
52
+ it 'build a + post aggregation' do
53
+ @query.postagg{(a + b).as ctr }
54
+ JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
55
+ "fn"=>"+",
56
+ "fields"=>
57
+ [{"type"=>"fieldAccess","name"=>"a", "fieldName"=>"a"},
58
+ {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
59
+ "name"=>"ctr"}]
60
+ end
61
+
62
+ it 'build a - post aggregation' do
63
+ @query.postagg{(a - b).as ctr }
64
+ JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
65
+ "fn"=>"-",
66
+ "fields"=>
67
+ [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
68
+ {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
69
+ "name"=>"ctr"}]
70
+ end
71
+
72
+ it 'build a * post aggregation' do
73
+ @query.postagg{(a * b).as ctr }
74
+ JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
75
+ "fn"=>"*",
76
+ "fields"=>
77
+ [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
78
+ {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
79
+ "name"=>"ctr"}]
80
+ end
62
81
 
63
- it 'build a - post aggregation' do
64
- @query.postagg{(a - b).as ctr }
65
- JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
66
- "fn"=>"-",
67
- "fields"=>
68
- [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
69
- {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
82
+ it 'build a / post aggregation' do
83
+ @query.postagg{(a / b).as ctr }
84
+ JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
85
+ "fn"=>"/",
86
+ "fields"=>
87
+ [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
88
+ {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
70
89
  "name"=>"ctr"}]
71
- end
90
+ end
72
91
 
73
- it 'build a * post aggregation' do
74
- @query.postagg{(a * b).as ctr }
75
- JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
76
- "fn"=>"*",
77
- "fields"=>
78
- [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
79
- {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
92
+ it 'build a complex post aggregation' do
93
+ @query.postagg{((a / b) * 1000).as ctr }
94
+ JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
95
+ "fn"=>"*",
96
+ "fields"=>
97
+ [{"type"=>"arithmetic", "fn"=>"/", "fields"=>
98
+ [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
99
+ {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}]},
100
+ {"type"=>"constant", "value"=>1000}],
80
101
  "name"=>"ctr"}]
81
- end
102
+ end
82
103
 
83
- it 'build a / post aggregation' do
84
- @query.postagg{(a / b).as ctr }
85
- JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
86
- "fn"=>"/",
87
- "fields"=>
88
- [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
89
- {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
90
- "name"=>"ctr"}]
91
- end
104
+ it 'adds fields required by the postagg operation to longsum' do
105
+ @query.postagg{ (a/b).as c }
106
+ JSON.parse(@query.to_json)['aggregations'].should == [
107
+ {"type"=>"longSum", "name"=>"a", "fieldName"=>"a"},
108
+ {"type"=>"longSum", "name"=>"b", "fieldName"=>"b"}
109
+ ]
110
+ end
92
111
 
93
- it 'build a complex post aggregation' do
94
- @query.postagg{((a / b) * 1000).as ctr }
95
- JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
96
- "fn"=>"*",
97
- "fields"=>
98
- [{"type"=>"arithmetic", "fn"=>"/", "fields"=>
112
+ it 'chains aggregations' do
113
+ @query.postagg{(a / b).as ctr }.postagg{(b / a).as rtc }
114
+
115
+ JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
116
+ "fn"=>"/",
117
+ "fields"=>
99
118
  [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
100
- {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}]},
101
- {"type"=>"constant", "value"=>1000}],
102
- "name"=>"ctr"}]
103
- end
104
-
105
- it 'adds fields required by the postagg operation to longsum' do
106
- @query.postagg{ (a/b).as c }
107
- JSON.parse(@query.to_json)['aggregations'].should == [{"type"=>"longSum", "name"=>"a", "fieldName"=>"a"},
108
- {"type"=>"longSum", "name"=>"b", "fieldName"=>"b"}]
109
- end
110
-
111
- it 'chains aggregations' do
112
- @query.postagg{(a / b).as ctr }.postagg{(b / a).as rtc }
113
-
114
- JSON.parse(@query.to_json)['postAggregations'].should == [{"type"=>"arithmetic",
115
- "fn"=>"/",
116
- "fields"=>
117
- [{"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"},
118
- {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
119
- "name"=>"ctr"},
120
- {"type"=>"arithmetic",
121
- "fn"=>"/",
122
- "fields"=>
123
- [{"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"},
124
- {"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"}],
125
- "name"=>"rtc"}
126
- ]
119
+ {"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"}],
120
+ "name"=>"ctr"},
121
+ {"type"=>"arithmetic",
122
+ "fn"=>"/",
123
+ "fields"=>
124
+ [{"type"=>"fieldAccess", "name"=>"b", "fieldName"=>"b"},
125
+ {"type"=>"fieldAccess", "name"=>"a", "fieldName"=>"a"}],
126
+ "name"=>"rtc"}
127
+ ]
128
+ end
129
+
130
+ it 'builds a javascript post aggregation' do
131
+ @query.postagg { js('function(agg1, agg2) { return agg1 + agg2; }').as result }
132
+ JSON.parse(@query.to_json)['postAggregations'].should == [
133
+ {
134
+ 'type' => 'javascript',
135
+ 'name' => 'result',
136
+ 'fieldNames' => ['agg1', 'agg2'],
137
+ 'function' => 'function(agg1, agg2) { return agg1 + agg2; }'
138
+ }
139
+ ]
140
+ end
141
+
142
+ it 'raises an error when an invalid javascript function is used' do
143
+ expect {
144
+ @query.postagg { js('{ return a_with_b - a; }').as b }
145
+ }.to raise_error
146
+ end
127
147
  end
128
148
 
129
149
  it 'builds aggregations on long_sum' do
@@ -135,7 +155,6 @@ describe Druid::Query do
135
155
  ]
136
156
  end
137
157
 
138
-
139
158
  it 'appends long_sum properties from aggregations on calling long_sum again' do
140
159
  @query.long_sum(:a, :b, :c)
141
160
  @query.double_sum(:x,:y)
@@ -368,11 +387,25 @@ end
368
387
  ]}
369
388
  end
370
389
 
371
- it 'creates a greater than having clause' do
372
- @query.having{a > 100}
373
- JSON.parse(@query.to_json)['having'].should == {
374
- "type"=>"greaterThan", "aggregation"=>"a", "value"=>100
375
- }
390
+ describe '#having' do
391
+ it 'creates a greater than having clause' do
392
+ @query.having{a > 100}
393
+ JSON.parse(@query.to_json)['having'].should == {
394
+ "type"=>"greaterThan", "aggregation"=>"a", "value"=>100
395
+ }
396
+ end
397
+
398
+ it 'chains having clauses with and' do
399
+ @query.having{a > 100}.having{b > 200}.having{c > 300}
400
+ JSON.parse(@query.to_json)['having'].should == {
401
+ "type" => "and",
402
+ "havingSpecs" => [
403
+ { "type" => "greaterThan", "aggregation" => "a", "value" => 100 },
404
+ { "type" => "greaterThan", "aggregation" => "b", "value" => 200 },
405
+ { "type" => "greaterThan", "aggregation" => "c", "value" => 300 }
406
+ ]
407
+ }
408
+ end
376
409
  end
377
410
 
378
411
  it 'does not accept in with empty array' do
@@ -1,5 +1,3 @@
1
- require "spec_helper"
2
-
3
1
  module ZK
4
2
  def self.new(uri, opts = {})
5
3
  Mock.new uri, opts
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-druid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - LiquidM, Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-09 00:00:00.000000000 Z
11
+ date: 2014-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zk
15
- version_requirements: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - '>='
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
15
  requirement: !ruby/object:Gem::Requirement
21
16
  requirements:
22
- - - '>='
17
+ - - ">="
23
18
  - !ruby/object:Gem::Version
24
19
  version: '0'
25
- prerelease: false
26
20
  type: :runtime
27
- - !ruby/object:Gem::Dependency
28
- name: rest-client
21
+ prerelease: false
29
22
  version_requirements: !ruby/object:Gem::Requirement
30
23
  requirements:
31
- - - '>='
24
+ - - ">="
32
25
  - !ruby/object:Gem::Version
33
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
34
29
  requirement: !ruby/object:Gem::Requirement
35
30
  requirements:
36
- - - '>='
31
+ - - ">="
37
32
  - !ruby/object:Gem::Version
38
33
  version: '0'
39
- prerelease: false
40
34
  type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
41
  description: Ruby client for metamx druid
42
42
  email:
43
43
  - opensource@liquidm.com
@@ -46,8 +46,9 @@ executables:
46
46
  extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
- - .gitignore
50
- - .travis.yml
49
+ - ".gitignore"
50
+ - ".rspec"
51
+ - ".travis.yml"
51
52
  - Gemfile
52
53
  - LICENSE
53
54
  - README.md
@@ -62,6 +63,7 @@ files:
62
63
  - lib/druid/post_aggregation.rb
63
64
  - lib/druid/query.rb
64
65
  - lib/druid/response_row.rb
66
+ - lib/druid/serializable.rb
65
67
  - lib/druid/zoo_handler.rb
66
68
  - ruby-druid.gemspec
67
69
  - spec/lib/client_spec.rb
@@ -72,24 +74,24 @@ homepage: https://github.com/liquidm/ruby-druid
72
74
  licenses:
73
75
  - MIT
74
76
  metadata: {}
75
- post_install_message:
77
+ post_install_message:
76
78
  rdoc_options: []
77
79
  require_paths:
78
80
  - lib
79
81
  required_ruby_version: !ruby/object:Gem::Requirement
80
82
  requirements:
81
- - - '>='
83
+ - - ">="
82
84
  - !ruby/object:Gem::Version
83
85
  version: '0'
84
86
  required_rubygems_version: !ruby/object:Gem::Requirement
85
87
  requirements:
86
- - - '>='
88
+ - - ">="
87
89
  - !ruby/object:Gem::Version
88
90
  version: '0'
89
91
  requirements: []
90
- rubyforge_project:
91
- rubygems_version: 2.2.2
92
- signing_key:
92
+ rubyforge_project:
93
+ rubygems_version: 2.1.11
94
+ signing_key:
93
95
  specification_version: 4
94
96
  summary: Ruby client for metamx druid
95
97
  test_files:
@@ -97,4 +99,4 @@ test_files:
97
99
  - spec/lib/query_spec.rb
98
100
  - spec/lib/zoo_handler_spec.rb
99
101
  - spec/spec_helper.rb
100
- has_rdoc:
102
+ has_rdoc: