keen 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@ rvm:
10
10
 
11
11
  env:
12
12
  - PATTERN=keen
13
- - PATTERN=integration KEEN_WRITE_KEY=f806128f31c349fda124b62d1f4cf4b2 KEEN_READ_KEY=f806128f31c349fda124b62d1f4cf4b2 KEEN_PROJECT_ID=50e5ffa6897a2c319b000000
13
+ - PATTERN=integration KEEN_MASTER_KEY=f806128f31c349fda124b62d1f4cf4b2 KEEN_WRITE_KEY=f806128f31c349fda124b62d1f4cf4b2 KEEN_READ_KEY=f806128f31c349fda124b62d1f4cf4b2 KEEN_PROJECT_ID=50e5ffa6897a2c319b000000
14
14
  - PATTERN=synchrony
15
15
 
16
16
  matrix:
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- keen (0.7.3)
4
+ keen (0.7.4)
5
5
  multi_json (~> 1.0)
6
6
 
7
7
  GEM
@@ -51,7 +51,7 @@ GEM
51
51
  rb-kqueue (>= 0.2)
52
52
  lumberjack (1.0.3)
53
53
  method_source (0.8.1)
54
- multi_json (1.7.3)
54
+ multi_json (1.7.4)
55
55
  pry (0.9.12.1)
56
56
  coderay (~> 1.0.5)
57
57
  method_source (~> 0.8)
data/README.md CHANGED
@@ -23,14 +23,22 @@ keen is tested with Ruby 1.8 and 1.9 on:
23
23
 
24
24
  ### Usage
25
25
 
26
- Before making any API calls, you must supply keen-gem with a Project ID and one or both of your Write and Read Keys.
27
- (If you need a Keen IO account, [sign up here](https://keen.io/) - it's free.) The Write key is required for publishing
28
- events, and the Read key is required for running queries.
26
+ Before making any API calls, you must supply keen-gem with a Project ID and one or more authentication keys.
27
+ (If you need a Keen IO account, [sign up here](https://keen.io/signup) - it's free.)
29
28
 
30
- The recommended way to do this is to set `KEEN_PROJECT_ID`, `KEEN_WRITE_KEY`, and `KEEN_READ_KEY` in your
31
- environment. If you're using [foreman](http://ddollar.github.com/foreman/), add this to your `.env` file:
29
+ Setting a write key is required for publishing events. Setting a read key is required for running queries.
30
+ Setting a master key is required for performing deletes. You can find keys for all of your projects
31
+ on [keen.io](https://keen.io).
32
32
 
33
- KEEN_PROJECT_ID=xxxxxxxxxxxxxxxx KEEN_WRITE_KEY=yyyyyyyyyyyyy KEEN_READ_KEY=zzzzzzzzzzzzz
33
+ The recommended way to set keys is via the environment. The keys you can set are
34
+ `KEEN_PROJECT_ID`, `KEEN_WRITE_KEY`, `KEEN_READ_KEY`, and `KEEN_MASTER_KEY`.
35
+ You only need to specify the keys that correspond to the API calls you'll be performing.
36
+ If you're using [foreman](http://ddollar.github.com/foreman/), add this to your `.env` file:
37
+
38
+ KEEN_PROJECT_ID=aaaaaaaaaaaaaaa
39
+ KEEN_MASTER_KEY=xxxxxxxxxxxxxxx
40
+ KEEN_WRITE_KEY=yyyyyyyyyyyyyyy
41
+ KEEN_READ_KEY=zzzzzzzzzzzzzzz
34
42
 
35
43
  If not, make to to export the variable into your shell or put it before the command you use to start your server.
36
44
 
@@ -38,23 +46,25 @@ When you deploy, make sure your production environment variables are set. For ex
38
46
  set [config vars](https://devcenter.heroku.com/articles/config-vars) on Heroku. (We recommend this
39
47
  environment-based approach because it keeps sensitive information out of the codebase. If you can't do this, see the alternatives below.)
40
48
 
41
- If your environment is set up property, `Keen` is ready to go immediately. Publish an event like this:
49
+ Once your environment is properly configured, the `Keen` object is ready to go immediately.
50
+
51
+ ### Publishing events
52
+
53
+ Publishing events requires that `KEEN_WRITE_KEY` is set. Publish an event like this:
42
54
 
43
55
  ```ruby
44
- Keen.publish("sign_ups", { :username => "lloyd", :referred_by => "harry" })
56
+ Keen.publish(:sign_ups, { :username => "lloyd", :referred_by => "harry" })
45
57
  ```
46
58
 
47
- This will publish an event to the 'sign_ups' collection with the `username` and `referred_by` properties set.
48
-
49
- The event properties are arbitrary JSON, and the event collection need not exist in advance.
50
- If it doesn't exist, Keen IO will create it on the first request.
59
+ This will publish an event to the `sign_ups` collection with the `username` and `referred_by` properties set.
60
+ The event properties can be any valid Ruby hash and nested properties are allowed. You can learn more about data modeling with Keen IO with the [Data Modeling Guide](https://keen.io/docs/event-data-modeling/event-data-intro/).
51
61
 
52
- You can learn more about data modeling with Keen IO with the [Data Modeling Guide](https://keen.io/docs/event-data-modeling/event-data-intro/).
62
+ The event collection need not exist in advance. If it doesn't exist, Keen IO will create it on the first request.
53
63
 
54
64
  ### Asynchronous publishing
55
65
 
56
- Publishing events shouldn't slow your application down. It shouldn't make your
57
- users wait longer for their request to finish.
66
+ Publishing events shouldn't slow your application down or make
67
+ users wait longer for page loads & server requests.
58
68
 
59
69
  The Keen IO API is fast, but any synchronous network call you make will
60
70
  negatively impact response times. For this reason, we recommend you use the `publish_async`
@@ -77,7 +87,7 @@ Thread.new { EventMachine.run }
77
87
  ```
78
88
 
79
89
  The best place for this is in an initializer, or anywhere that runs when your app boots up.
80
- Here's a good blog article that explains more about this approach - [EventMachine and Passenger](http://railstips.org/blog/archives/2011/05/04/eventmachine-and-passenger/).
90
+ Here's a useful blog article that explains more about this approach - [EventMachine and Passenger](http://railstips.org/blog/archives/2011/05/04/eventmachine-and-passenger/).
81
91
 
82
92
  And here's a gist that shows an example of [Eventmachine with Unicorn](https://gist.github.com/jonkgrimes/5103321). Thanks to [jonkgrimes](https://github.com/jonkgrimes) for sharing this with us!
83
93
 
@@ -96,11 +106,9 @@ to resume processing immediately.
96
106
 
97
107
  The Keen IO API provides rich querying capabilities against your event data set. For more information, see the [Data Analysis API Guide](https://keen.io/docs/data-analysis/).
98
108
 
99
- Queries require that a Read Key is provided. Just like project ID, we encourage that you set this as an environment variable:
109
+ Running queries requires that `KEEN_READ_KEY` is set.
100
110
 
101
- KEEN_READ_KEY=yyyyyyyyyyyyyyyy
102
-
103
- Here's are some examples of querying with keen-gem. Let's assume you've added some events to the "purchases" collection.
111
+ Here are some examples of querying with keen-gem. Let's assume you've added some events to the "purchases" collection.
104
112
 
105
113
  ```ruby
106
114
  Keen.count("purchases") # => 100
@@ -112,7 +120,7 @@ Keen.average("purchases", :target_property => "price") # => 60
112
120
  Keen.sum("purchases", :target_property => "price", :group_by => "item.id") # => [{ "item.id": 123, "result": 240 }, { ... }]
113
121
 
114
122
  Keen.count_unique("purchases", :target_property => "username") # => 3
115
- Keen.select_unique("purchases", :target_property => "username") # => ["bob", "linda", "travis"]
123
+ Keen.select_unique("purchases", :target_property => "username") # => ["Bob", "Linda", "Travis"]
116
124
 
117
125
  Keen.extraction("purchases") # => [{ "price" => 20, ... }, { ... }]
118
126
 
@@ -127,10 +135,29 @@ Keen.multi_analysis("purchases", analyses: {
127
135
  :timeframe => 'today', :group_by => "item.id") # => [{"item.id"=>2, "gross"=>314.49, "customers"=> 8}, { ... }]
128
136
  ```
129
137
 
130
- Many of there queries can be performed with group by, filters, series and intervals. The API response for these is converted directly into Ruby Hash or Array.
138
+ Many of there queries can be performed with group by, filters, series and intervals. The response is returned as a Ruby Hash or Array.
131
139
 
132
140
  Detailed information on available parameters for each API resource can be found on the [API Technical Reference](https://keen.io/docs/api/reference/).
133
141
 
142
+ ### Deleting events
143
+
144
+ The Keen IO API allows you to [delete events](https://keen.io/docs/maintenance/#deleting-event-collections)
145
+ from event collections, optionally supplying a filter to narrow the scope of what you would like to delete.
146
+
147
+ Deleting events requires that the `KEEN_MASTER_KEY` is set.
148
+
149
+ ```ruby
150
+ # Assume some events in the 'signups' collection
151
+
152
+ # We can delete them all
153
+ Keen.delete(:signups) # => true
154
+
155
+ # Or just delete an event corresponding to a particular user
156
+ Keen.delete(:signups, filters: [{
157
+ property_name: 'username', operator: 'eq', property_value: "Bob"
158
+ }]) # => true
159
+ ```
160
+
134
161
  ### Other code examples
135
162
 
136
163
  #### Batch publishing
@@ -153,7 +180,7 @@ Keen.publish_batch(
153
180
  This call would publish 2 `signups` events and 2 `purchases` events - all in just one API call.
154
181
  Batch publishing is ideal for loading historical events into Keen IO.
155
182
 
156
- #### Authentication
183
+ #### Configurable and per-client authentication
157
184
 
158
185
  To configure keen-gem in code, do as follows:
159
186
 
@@ -161,14 +188,16 @@ To configure keen-gem in code, do as follows:
161
188
  Keen.project_id = 'xxxxxxxxxxxxxxx'
162
189
  Keen.write_key = 'yyyyyyyyyyyyyyy'
163
190
  Keen.read_key = 'zzzzzzzzzzzzzzz'
191
+ Keen.master_key = 'aaaaaaaaaaaaaaa'
164
192
  ```
165
193
 
166
- You can also configure individual client instances as follows:
194
+ You can also configure unique client instances as follows:
167
195
 
168
196
  ```ruby
169
197
  keen = Keen::Client.new(:project_id => 'xxxxxxxxxxxxxxx',
170
198
  :write_key => 'yyyyyyyyyyyyyyy',
171
- :read_key => 'zzzzzzzzzzzzzzz')
199
+ :read_key => 'zzzzzzzzzzzzzzz',
200
+ :master_key => 'aaaaaaaaaaaaaaa')
172
201
  ```
173
202
 
174
203
  #### em-synchrony
@@ -197,6 +226,10 @@ To track email opens, simply add an image to your email template that points to
197
226
 
198
227
  ### Changelog
199
228
 
229
+ ##### 0.7.4
230
+ + Add support for deletes (thanks again [cbartlett](https://github.com/cbartlett)!)
231
+ + Allow event collection names for publishing/deleting methods to be symbols
232
+
200
233
  ##### 0.7.3
201
234
  + Add batch publishing support
202
235
  + Allow event collection names for querying methods to be symbols. Thanks to [cbartlett](https://github.com/cbartlett).
@@ -40,6 +40,9 @@ module Keen
40
40
  :sum, :average, :select_unique, :funnel, :extraction,
41
41
  :multi_analysis
42
42
 
43
+ def_delegators :default_client,
44
+ :delete
45
+
43
46
  attr_writer :logger
44
47
 
45
48
  def logger
@@ -57,6 +60,7 @@ module Keen
57
60
  :project_id => ENV['KEEN_PROJECT_ID'],
58
61
  :write_key => ENV['KEEN_WRITE_KEY'],
59
62
  :read_key => ENV['KEEN_READ_KEY'],
63
+ :master_key => ENV['KEEN_MASTER_KEY'],
60
64
  :api_url => ENV['KEEN_API_URL']
61
65
  )
62
66
  end
@@ -2,6 +2,7 @@ require 'keen/http'
2
2
  require 'keen/version'
3
3
  require 'keen/client/publishing_methods'
4
4
  require 'keen/client/querying_methods'
5
+ require 'keen/client/maintenance_methods'
5
6
 
6
7
  require 'openssl'
7
8
  require 'multi_json'
@@ -11,8 +12,9 @@ module Keen
11
12
  class Client
12
13
  include Keen::Client::PublishingMethods
13
14
  include Keen::Client::QueryingMethods
15
+ include Keen::Client::MaintenanceMethods
14
16
 
15
- attr_accessor :project_id, :write_key, :read_key, :api_url
17
+ attr_accessor :project_id, :write_key, :read_key, :master_key, :api_url
16
18
 
17
19
  CONFIG = {
18
20
  :api_url => "https://api.keen.io",
@@ -40,8 +42,8 @@ module Keen
40
42
  }.merge(args[3] || {})
41
43
  end
42
44
 
43
- self.project_id, self.write_key, self.read_key = options.values_at(
44
- :project_id, :write_key, :read_key)
45
+ self.project_id, self.write_key, self.read_key, self.master_key = options.values_at(
46
+ :project_id, :write_key, :read_key, :master_key)
45
47
 
46
48
  self.api_url = options[:api_url] || CONFIG[:api_url]
47
49
  end
@@ -57,6 +59,8 @@ module Keen
57
59
  Keen.logger.warn("Invalid JSON for response code #{status_code}: #{response_body}")
58
60
  return {}
59
61
  end
62
+ when 204
63
+ return true
60
64
  when 400
61
65
  raise BadRequestError.new(response_body)
62
66
  when 401
@@ -76,10 +80,44 @@ module Keen
76
80
  raise ConfigurationError, "Write Key must be set for sending events" unless self.write_key
77
81
  end
78
82
 
83
+ def ensure_master_key!
84
+ raise ConfigurationError, "Master Key must be set for delete event collections" unless self.master_key
85
+ end
86
+
79
87
  def ensure_read_key!
80
88
  raise ConfigurationError, "Read Key must be set for queries" unless self.read_key
81
89
  end
82
90
 
91
+ def api_event_collection_resource_path(event_collection)
92
+ "/#{api_version}/projects/#{project_id}/events/#{URI.escape(event_collection.to_s)}"
93
+ end
94
+
95
+ def preprocess_params(params)
96
+ if params.key?(:filters)
97
+ params[:filters] = MultiJson.encode(params[:filters])
98
+ end
99
+
100
+ if params.key?(:steps)
101
+ params[:steps] = MultiJson.encode(params[:steps])
102
+ end
103
+
104
+ if params.key?(:analyses)
105
+ params[:analyses] = MultiJson.encode(params[:analyses])
106
+ end
107
+
108
+ if params.key?(:timeframe) && params[:timeframe].is_a?(Hash)
109
+ params[:timeframe] = MultiJson.encode(params[:timeframe])
110
+ end
111
+
112
+ query_params = ""
113
+ params.each do |param, value|
114
+ query_params << "#{param}=#{URI.escape(value)}&"
115
+ end
116
+
117
+ query_params.chop!
118
+ query_params
119
+ end
120
+
83
121
  def method_missing(_method, *args, &block)
84
122
  if config = CONFIG[_method.to_sym]
85
123
  if config.is_a?(Proc)
@@ -0,0 +1,31 @@
1
+ module Keen
2
+ class Client
3
+ module MaintenanceMethods
4
+
5
+ # Runs a delete query.
6
+ # See detailed documentation here:
7
+ # https://keen.io/docs/maintenance/#deleting-event-collections
8
+ #
9
+ # @param event_collection
10
+ # @param params [Hash] (optional)
11
+ # filters (optional) [Array]
12
+ def delete(event_collection, params={})
13
+ ensure_project_id!
14
+ ensure_master_key!
15
+
16
+ query_params = preprocess_params(params) if params != {}
17
+
18
+ begin
19
+ response = Keen::HTTP::Sync.new(self.api_url).delete(
20
+ :path => [api_event_collection_resource_path(event_collection), query_params].compact.join('?'),
21
+ :headers => api_headers(self.master_key, "sync"))
22
+ rescue Exception => http_error
23
+ raise HttpError.new("Couldn't perform delete of #{event_collection} on Keen IO: #{http_error.message}", http_error)
24
+ end
25
+
26
+ response_body = response.body ? response.body.chomp : ''
27
+ process_response(response.code, response_body)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -126,10 +126,6 @@ module Keen
126
126
  process_response(response.code, response.body.chomp)
127
127
  end
128
128
 
129
- def api_event_collection_resource_path(event_collection)
130
- "/#{api_version}/projects/#{project_id}/events/#{URI.escape(event_collection)}"
131
- end
132
-
133
129
  def api_events_resource_path
134
130
  "/#{api_version}/projects/#{project_id}/events"
135
131
  end
@@ -182,32 +182,6 @@ module Keen
182
182
  process_response(response.code, response_body)["result"]
183
183
  end
184
184
 
185
- def preprocess_params(params)
186
- if params.key?(:filters)
187
- params[:filters] = MultiJson.encode(params[:filters])
188
- end
189
-
190
- if params.key?(:steps)
191
- params[:steps] = MultiJson.encode(params[:steps])
192
- end
193
-
194
- if params.key?(:analyses)
195
- params[:analyses] = MultiJson.encode(params[:analyses])
196
- end
197
-
198
- if params.key?(:timeframe) && params[:timeframe].is_a?(Hash)
199
- params[:timeframe] = MultiJson.encode(params[:timeframe])
200
- end
201
-
202
- query_params = ""
203
- params.each do |param, value|
204
- query_params << "#{param}=#{URI.escape(value)}&"
205
- end
206
-
207
- query_params.chop!
208
- query_params
209
- end
210
-
211
185
  def api_query_resource_path(analysis_type)
212
186
  "/#{self.api_version}/projects/#{self.project_id}/queries/#{analysis_type}"
213
187
  end
@@ -28,6 +28,12 @@ module Keen
28
28
  :path, :headers)
29
29
  @http.get(path, headers)
30
30
  end
31
+
32
+ def delete(options)
33
+ path, headers = options.values_at(
34
+ :path, :headers)
35
+ @http.delete(path, headers)
36
+ end
31
37
  end
32
38
 
33
39
  class Async
@@ -1,3 +1,3 @@
1
1
  module Keen
2
- VERSION = "0.7.3"
2
+ VERSION = "0.7.4"
3
3
  end
@@ -164,4 +164,25 @@ describe "Keen IO API" do
164
164
  }]).should == 1
165
165
  end
166
166
  end
167
+
168
+ describe "deletes" do
169
+ let(:event_collection) { "delete_test_#{rand(10000)}" }
170
+
171
+ before do
172
+ Keen.publish(event_collection, :delete => "me")
173
+ Keen.publish(event_collection, :delete => "you")
174
+ sleep(3)
175
+ end
176
+
177
+ it "should delete the event" do
178
+ Keen.count(event_collection).should == 2
179
+ Keen.delete(event_collection, :filters => [
180
+ { :property_name => "delete", :operator => "eq", :property_value => "me" }
181
+ ])
182
+ sleep(3)
183
+ results = Keen.extraction(event_collection)
184
+ results.length.should == 1
185
+ results.first["delete"].should == "you"
186
+ end
187
+ end
167
188
  end
@@ -0,0 +1,38 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe Keen::Client do
4
+ let(:project_id) { "12345" }
5
+ let(:master_key) { 'pastor_of_muppets' }
6
+ let(:api_url) { "https://notreal.keen.io" }
7
+ let(:api_version) { "3.0" }
8
+ let(:client) { Keen::Client.new(
9
+ :project_id => project_id, :master_key => master_key,
10
+ :api_url => api_url ) }
11
+
12
+ def delete_url(event_collection, filter_params=nil)
13
+ "#{api_url}/#{api_version}/projects/#{project_id}/events/#{event_collection}#{filter_params ? "?filters=#{URI.escape(MultiJson.encode(filter_params[:filters]))}" : ""}"
14
+ end
15
+
16
+ describe '#delete' do
17
+ let(:event_collection) { :foodstuffs }
18
+
19
+ it 'should not require filters' do
20
+ url = delete_url(event_collection)
21
+ stub_keen_delete(url, 204)
22
+ client.delete(event_collection).should be_true
23
+ expect_keen_delete(url, "sync", master_key)
24
+ end
25
+
26
+ it "should accept and use filters" do
27
+ filters = {
28
+ :filters => [
29
+ { :property_name => "delete", :operator => "eq", :property_value => "me" }
30
+ ]
31
+ }
32
+ url = delete_url(event_collection, filters)
33
+ stub_keen_delete(url, 204).should be_true
34
+ client.delete(event_collection, filters)
35
+ expect_keen_delete(url, "sync", master_key)
36
+ end
37
+ end
38
+ end
@@ -23,6 +23,10 @@ module Keen::SpecHelpers
23
23
  stub_keen_request(:get, url, status, MultiJson.encode(response_body))
24
24
  end
25
25
 
26
+ def stub_keen_delete(url, status)
27
+ stub_keen_request(:delete, url, status, "")
28
+ end
29
+
26
30
  def expect_keen_request(method, url, body, sync_or_async_ua, read_or_write_key)
27
31
  user_agent = "keen-gem, v#{Keen::VERSION}, #{sync_or_async_ua}"
28
32
  user_agent += ", #{RUBY_VERSION}, #{RUBY_PLATFORM}, #{RUBY_PATCHLEVEL}"
@@ -48,6 +52,10 @@ module Keen::SpecHelpers
48
52
  expect_keen_request(:post, url, MultiJson.encode(event_properties), sync_or_async_ua, write_key)
49
53
  end
50
54
 
55
+ def expect_keen_delete(url, sync_or_async_ua, master_key)
56
+ expect_keen_request(:delete, url, "", sync_or_async_ua, master_key)
57
+ end
58
+
51
59
  def api_event_collection_resource_url(base_url, collection)
52
60
  "#{base_url}/3.0/projects/#{project_id}/events/#{collection}"
53
61
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-05-17 00:00:00.000000000 Z
14
+ date: 2013-05-31 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: multi_json
@@ -48,12 +48,14 @@ files:
48
48
  - keen.gemspec
49
49
  - lib/keen.rb
50
50
  - lib/keen/client.rb
51
+ - lib/keen/client/maintenance_methods.rb
51
52
  - lib/keen/client/publishing_methods.rb
52
53
  - lib/keen/client/querying_methods.rb
53
54
  - lib/keen/http.rb
54
55
  - lib/keen/version.rb
55
56
  - spec/integration/api_spec.rb
56
57
  - spec/integration/spec_helper.rb
58
+ - spec/keen/client/maintenance_methods_spec.rb
57
59
  - spec/keen/client/publishing_methods_spec.rb
58
60
  - spec/keen/client/querying_methods_spec.rb
59
61
  - spec/keen/client_spec.rb
@@ -89,6 +91,7 @@ summary: Keen IO API Client
89
91
  test_files:
90
92
  - spec/integration/api_spec.rb
91
93
  - spec/integration/spec_helper.rb
94
+ - spec/keen/client/maintenance_methods_spec.rb
92
95
  - spec/keen/client/publishing_methods_spec.rb
93
96
  - spec/keen/client/querying_methods_spec.rb
94
97
  - spec/keen/client_spec.rb