orchestrate 0.5
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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +115 -0
- data/Rakefile +20 -0
- data/lib/orchestrate.rb +46 -0
- data/lib/orchestrate/api.rb +15 -0
- data/lib/orchestrate/api/errors.rb +57 -0
- data/lib/orchestrate/api/extensions.rb +14 -0
- data/lib/orchestrate/client.rb +410 -0
- data/lib/orchestrate/configuration.rb +53 -0
- data/lib/orchestrate/helpers.rb +22 -0
- data/lib/orchestrate/version.rb +3 -0
- data/orchestrate.gemspec +27 -0
- data/test/orchestrate/api/collections_test.rb +87 -0
- data/test/orchestrate/api/event_test.rb +133 -0
- data/test/orchestrate/api/graph_test.rb +44 -0
- data/test/orchestrate/api/key_value_test.rb +173 -0
- data/test/orchestrate/client_test.rb +40 -0
- data/test/orchestrate/configuration_test.rb +67 -0
- data/test/test_helper.rb +80 -0
- metadata +181 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d745f6432de35d38a03090bad7e072c5050f2660
|
4
|
+
data.tar.gz: b48814208a0b00a4c4d80bad1ea1e0a7d9c3e51c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 99d1b6e4fffed62524458cd0862fc71d0d6f3d6cdc2187ce8882007159bbddfda38cac003f304ffb53e75fa8fceda1a8fe389963c6ff50448db84f796c112e16
|
7
|
+
data.tar.gz: c5f59656dc41f5b4eab6f9840a838b69938e20ac50d9d3c8cf44d0e337a946de98e4290260dd2e64b19c43b56351a86e0dc59515035f6554f2673e2d555a9419
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 jimcar
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
Orchestrate API for Ruby
|
2
|
+
========================
|
3
|
+
[](https://travis-ci.org/orchestrate-io/orchestrate-ruby)
|
4
|
+
|
5
|
+
Ruby client interface for the [Orchestrate.io](http://orchestrate.io) REST API.
|
6
|
+
|
7
|
+
[rDoc Documentation](http://rdoc.info/github/orchestrate-io/orchestrate-ruby/master/frames)
|
8
|
+
|
9
|
+
## Getting Started
|
10
|
+
|
11
|
+
Provide your API key:
|
12
|
+
|
13
|
+
``` ruby
|
14
|
+
Orchestrate::Configuration.api_key = '8ce391a...'
|
15
|
+
```
|
16
|
+
|
17
|
+
Create a client:
|
18
|
+
|
19
|
+
``` ruby
|
20
|
+
client = Orchestrate::Client.new
|
21
|
+
```
|
22
|
+
|
23
|
+
and start making requests:
|
24
|
+
|
25
|
+
``` ruby
|
26
|
+
client.list(:my_collection)
|
27
|
+
```
|
28
|
+
|
29
|
+
## Swapping out the HTTP backend
|
30
|
+
|
31
|
+
This gem uses [Faraday][] for its HTTP needs -- and Faraday allows you to change the underlying HTTP client used. It defaults to `Net::HTTP` but if you wanted to use [Typhoeus][] or [EventMachine HTTP][em-http], doing so would be easy. Alternate Faraday backends enable using callbacks or parallel request support.
|
32
|
+
|
33
|
+
In your Orchestrate configuration, simply provide a `faraday` key with a block that will be called with the `Faraday::Connection` object. You may decorate it with middleware or change the adapter as described in the Faraday README. Examples are below.
|
34
|
+
|
35
|
+
You may use Faraday's `test` adapter to stub out calls to the Orchestrate API in your tests. See `tests/test_helper.rb` and the tests in `tests/orchestrate/api/*_test.rb` for examples.
|
36
|
+
|
37
|
+
[Faraday]: https://github.com/lostisland/faraday/
|
38
|
+
[Typhoeus]: https://github.com/typhoeus/typhoeus#readme
|
39
|
+
[em-http]: https://github.com/igrigorik/em-http-request#readme
|
40
|
+
|
41
|
+
### Parallel HTTP requests
|
42
|
+
|
43
|
+
If you're using a Faraday backend that enables parallelization, such as Typhoeus, EM-HTTP-Request, or EM-Synchrony you can use `Orchestrate::Client#in_parallel` to fire off multiple requests at once. If your Faraday backend does not support this, the method will still work as expected, but Faraday will output a warning to STDERR and the requests will be performed in series.
|
44
|
+
|
45
|
+
``` ruby
|
46
|
+
client = Orchestrate::Client.new
|
47
|
+
|
48
|
+
responses = client.in_parallel do |r|
|
49
|
+
r[:list] = client.list(:my_collection)
|
50
|
+
r[:user] = client.get(:users, current_user_id)
|
51
|
+
r[:user_events] = client.list_events(:users, current_user_id, :notices)
|
52
|
+
end
|
53
|
+
# will return when all requests have completed
|
54
|
+
|
55
|
+
responses[:user] = #<Faraday::Response:0x00...>
|
56
|
+
```
|
57
|
+
|
58
|
+
### Callback Support
|
59
|
+
|
60
|
+
If you're using a Faraday backend that enables callbacks, such as EM-HTTP-Request or EM-Synchrony, you may use the callback interface to designate actions to perform when the request completes.
|
61
|
+
|
62
|
+
``` ruby
|
63
|
+
client = Orchestrate::Client.new
|
64
|
+
response = client.list(:my_collection)
|
65
|
+
response.finished? # false
|
66
|
+
response.on_complete do
|
67
|
+
# do stuff with the response as normal
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
If the Faraday backend adapter does not support callbacks, the block provided will be executed when `Orchestrate::Client#on_complete` is called.
|
72
|
+
|
73
|
+
|
74
|
+
### Using with Typhoeus
|
75
|
+
|
76
|
+
Typhoeus is backed by libcurl and enables parallelization.
|
77
|
+
|
78
|
+
``` ruby
|
79
|
+
require 'typhoeus'
|
80
|
+
require 'typhoeus/adapters/faraday'
|
81
|
+
|
82
|
+
Orchestrate.configure do |config|
|
83
|
+
config.faraday = {|f| f.adapter :typhoeus }
|
84
|
+
config.api_key = "my_api_key"
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
### Using with EM-HTTP-Request
|
89
|
+
|
90
|
+
EM-HTTP-Request is an HTTP client for Event Machine. It enables callback support and parallelization.
|
91
|
+
|
92
|
+
|
93
|
+
``` ruby
|
94
|
+
require 'em-http-request'
|
95
|
+
|
96
|
+
Orchestrate.configure do |config|
|
97
|
+
config.faraday = {|f| f.adapter :em_http }
|
98
|
+
config.api_key = "my_api_key"
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
### Using with EM-Syncrony
|
103
|
+
|
104
|
+
EM-Synchrony is a collection of utility classes for EventMachine to help untangle evented code. It enables parallelization.
|
105
|
+
|
106
|
+
``` ruby
|
107
|
+
require 'em-synchrony'
|
108
|
+
|
109
|
+
Orchestrate.configure do |config|
|
110
|
+
config.faraday = {|f| f.adapter :em_synchrony }
|
111
|
+
config.api_key = "my_api_key"
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
require "rdoc/task"
|
4
|
+
|
5
|
+
task default: :test
|
6
|
+
|
7
|
+
Rake::TestTask.new do |test|
|
8
|
+
test.libs << "test"
|
9
|
+
test.test_files = FileList["test/**/*_test.rb"]
|
10
|
+
test.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
Rake::RDocTask.new(rdoc: "doc", clobber_rdoc: "doc:clean", rerdoc: "doc:force") do |rdoc|
|
14
|
+
rdoc.main = "README.md"
|
15
|
+
rdoc.title = "Orchestrate API Documentation"
|
16
|
+
rdoc.options << "--line-numbers"
|
17
|
+
rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
|
18
|
+
rdoc.rdoc_dir = "doc"
|
19
|
+
end
|
20
|
+
|
data/lib/orchestrate.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "orchestrate/api"
|
2
|
+
require "orchestrate/client"
|
3
|
+
require "orchestrate/configuration"
|
4
|
+
require "orchestrate/helpers"
|
5
|
+
require "orchestrate/version"
|
6
|
+
|
7
|
+
#
|
8
|
+
# A library for supporting connections to the \Orchestrate API.
|
9
|
+
#
|
10
|
+
module Orchestrate
|
11
|
+
|
12
|
+
# Configuration ------------------------------------------------------------
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
#
|
17
|
+
# An instance of Configuration containing the current library
|
18
|
+
# configuration options.
|
19
|
+
#
|
20
|
+
attr_accessor :config
|
21
|
+
|
22
|
+
#
|
23
|
+
# Lazily initialize and return the Configuration instance.
|
24
|
+
#
|
25
|
+
def config # :nodoc:
|
26
|
+
@config ||= Configuration.new
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Configure the Orchestrate library. This method should be called during
|
31
|
+
# application or script initialization. At a bare minimum, the Orchestrate
|
32
|
+
# library will require that an API key is provided.
|
33
|
+
#
|
34
|
+
# ==== Example
|
35
|
+
#
|
36
|
+
# Orchestrate.configure do |config|
|
37
|
+
# config.api_key = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
def configure
|
41
|
+
yield config
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "orchestrate"
|
2
|
+
require "orchestrate/api/extensions"
|
3
|
+
|
4
|
+
module Orchestrate
|
5
|
+
|
6
|
+
#
|
7
|
+
# Ruby gem +orchestrate-api+ provides an interface to the
|
8
|
+
# [Orchestrate](http://orchestrate.io) API.
|
9
|
+
#
|
10
|
+
# The Client class is used to setup the client and make HTTP requests.
|
11
|
+
#
|
12
|
+
module API
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Orchestrate::API
|
2
|
+
|
3
|
+
# Not used. But it does contain nice summary of orchestrate.io api errors.
|
4
|
+
#
|
5
|
+
module Error
|
6
|
+
def errors
|
7
|
+
@@errors ||= [
|
8
|
+
{ :status => 400,
|
9
|
+
:code => :api_bad_request,
|
10
|
+
:desc => 'The API request is malformed.'
|
11
|
+
},
|
12
|
+
{ :status => 500,
|
13
|
+
:code => :security_authentication,
|
14
|
+
:desc => 'An error occurred while trying to authenticate.'
|
15
|
+
},
|
16
|
+
{ :status => 401,
|
17
|
+
:code => :security_unauthorized,
|
18
|
+
:desc => 'Valid credentials are required.'
|
19
|
+
},
|
20
|
+
{ :status => 400,
|
21
|
+
:code => :search_param_invalid,
|
22
|
+
:desc => 'A provided search query param is invalid.'
|
23
|
+
},
|
24
|
+
{ :status => 500,
|
25
|
+
:code => :search_index_not_found,
|
26
|
+
:desc => 'Index could not be queried for this application.'
|
27
|
+
},
|
28
|
+
{ :status => 500,
|
29
|
+
:code => :internal_error,
|
30
|
+
:desc => 'Internal Error.'
|
31
|
+
},
|
32
|
+
{ :status => 404,
|
33
|
+
:code => :items_not_found,
|
34
|
+
:desc => 'The requested items could not be found.'
|
35
|
+
},
|
36
|
+
{ :status => 412,
|
37
|
+
:code => :item_version_mismatch,
|
38
|
+
:desc => 'The version of the item does not match.'
|
39
|
+
},
|
40
|
+
{ :status => 412,
|
41
|
+
:code => :item_already_present,
|
42
|
+
:desc => 'The item is already present.'
|
43
|
+
},
|
44
|
+
{ :status => 400,
|
45
|
+
:code => :item_ref_malformed,
|
46
|
+
:desc => 'The provided Item Ref is malformed.'
|
47
|
+
},
|
48
|
+
{ :status => 409,
|
49
|
+
:code => :indexing_conflict,
|
50
|
+
:desc => 'The item has been stored but conflicts were detected ' +
|
51
|
+
'when indexing. Conflicting fields have not been indexed.'
|
52
|
+
},
|
53
|
+
]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,410 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
|
4
|
+
module Orchestrate
|
5
|
+
|
6
|
+
# ==== Ruby Client for the Orchestrate REST *API*.
|
7
|
+
#
|
8
|
+
# The primary entry point is the #send_request method, which generates a
|
9
|
+
# Request, and returns the Response to the caller.
|
10
|
+
#
|
11
|
+
class Client
|
12
|
+
|
13
|
+
# Orchestrate::Configuration instance for the client. If not explicitly
|
14
|
+
# provided during initialization, will default to Orchestrate.config
|
15
|
+
attr_accessor :config
|
16
|
+
|
17
|
+
# The Faraday HTTP "connection" for the client.
|
18
|
+
attr_accessor :http
|
19
|
+
|
20
|
+
# Initialize and return a new Client instance. Optionally, configure
|
21
|
+
# options for the instance by passing a Configuration object. If no
|
22
|
+
# custom configuration is provided, the configuration options from
|
23
|
+
# Orchestrate.config will be used.
|
24
|
+
def initialize(config = Orchestrate.config)
|
25
|
+
@config = config
|
26
|
+
|
27
|
+
@http = Faraday.new(config.base_url) do |faraday|
|
28
|
+
if config.faraday.respond_to?(:call)
|
29
|
+
config.faraday.call(faraday)
|
30
|
+
else
|
31
|
+
faraday.adapter Faraday.default_adapter
|
32
|
+
end
|
33
|
+
|
34
|
+
# faraday seems to want you do specify these twice.
|
35
|
+
faraday.request :basic_auth, config.api_key, ''
|
36
|
+
faraday.basic_auth config.api_key, ''
|
37
|
+
|
38
|
+
# parses JSON responses
|
39
|
+
faraday.response :json, :content_type => /\bjson$/
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# -------------------------------------------------------------------------
|
44
|
+
# collection
|
45
|
+
|
46
|
+
# call-seq:
|
47
|
+
# client.list(collection_name, parameters = {}) -> response
|
48
|
+
#
|
49
|
+
# Performes a List query against the given collection. Results are sorted
|
50
|
+
# lexicographically by key name.
|
51
|
+
#
|
52
|
+
# +collection_name+:: A String or Symbol representing the name of the collection.
|
53
|
+
# +parameters+:: a Hash object containing query parameters:
|
54
|
+
# - +:limit+ - integer, number of results to return. Defaults to 10, Max 100.
|
55
|
+
# - +:start+ - string, start key of query range, including value.
|
56
|
+
# - +:after+ - string, start key of query range, excluding value.
|
57
|
+
# - +:before+ - string, end key of query range, excluding value.
|
58
|
+
# - +:end+ - string, end key of query range, including value.
|
59
|
+
#
|
60
|
+
# Note, you cannot provide *both* 'start' and 'after', or 'before' and 'end'
|
61
|
+
#
|
62
|
+
def list(collection, options={})
|
63
|
+
Orchestrate::Helpers.range_keys!('key', options)
|
64
|
+
send_request :get, [collection], { query: options }
|
65
|
+
end
|
66
|
+
|
67
|
+
# call-seq:
|
68
|
+
# client.list(collection_name, query, parameters = {}) -> response
|
69
|
+
#
|
70
|
+
# Performs a Search query against the given collection.
|
71
|
+
#
|
72
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
73
|
+
# +query+:: a String containing a Lucene query
|
74
|
+
# +parameters+:: a Hash object containing additional parameters:
|
75
|
+
# - +limit+: - integer, number of results to return. Defaults to 10, Max 100.
|
76
|
+
# - +offset+: - ingeger, the starting position of the results. Defaults to 0.
|
77
|
+
#
|
78
|
+
def search(collection, query, parameters={})
|
79
|
+
send_request :get, [collection], { query: parameters.merge({query: query})}
|
80
|
+
end
|
81
|
+
|
82
|
+
# call-seq:
|
83
|
+
# client.delete_collection(collection_name) -> response
|
84
|
+
#
|
85
|
+
# Deletes the given collection.
|
86
|
+
#
|
87
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
88
|
+
#
|
89
|
+
def delete_collection(collection)
|
90
|
+
send_request :delete, [collection], { query: {force:true} }
|
91
|
+
end
|
92
|
+
|
93
|
+
# -------------------------------------------------------------------------
|
94
|
+
# Key/Value
|
95
|
+
|
96
|
+
# call-seq:
|
97
|
+
# client.get(collection_name, key) -> response
|
98
|
+
# client.get(collection_name, key, ref) -> response
|
99
|
+
#
|
100
|
+
# Retreieves a value assigned to a key.
|
101
|
+
#
|
102
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
103
|
+
# +key+:: a String or Symbol representing the key for the value.
|
104
|
+
# +ref+:: if given, returns the value for the key at the specified ref. If omitted, returns the latest value for the key.
|
105
|
+
#
|
106
|
+
def get(collection, key, ref=nil)
|
107
|
+
if ref
|
108
|
+
send_request :get, [collection, key, 'refs', ref]
|
109
|
+
else
|
110
|
+
send_request :get, [collection, key]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# call-seq:
|
115
|
+
# client.put(collection_name, key, body) -> response
|
116
|
+
# client.put(collection_name, key, body, condition) -> response
|
117
|
+
#
|
118
|
+
# Creates or Updates the value at the specified key.
|
119
|
+
#
|
120
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
121
|
+
# +key+:: a String or Symbol representing the key for the value.
|
122
|
+
# +body+:: a Hash object representing the value for the key.
|
123
|
+
# +condition+::
|
124
|
+
# - +nil+ - the value for the specified key will be updated regardless.
|
125
|
+
# - String - used as 'If-Match'. The value will only be updated if the Key's current Value's Ref matches the given condition.
|
126
|
+
# - false - used as 'If-None-Match'. The value will only be created for the key if the key currently has no value.
|
127
|
+
#
|
128
|
+
def put(collection, key, body, condition=nil)
|
129
|
+
headers={}
|
130
|
+
if condition.is_a?(String)
|
131
|
+
headers['If-Match'] = format_ref(condition)
|
132
|
+
elsif condition == false
|
133
|
+
headers['If-None-Match'] = '*'
|
134
|
+
end
|
135
|
+
send_request :put, [collection, key], { body: body, headers: headers }
|
136
|
+
end
|
137
|
+
alias :put_if_unmodified :put
|
138
|
+
|
139
|
+
# call-seq:
|
140
|
+
# client.put_if_absent(collection_name, key, body) -> response
|
141
|
+
#
|
142
|
+
# Will create the value at the specified key only if there is no existing value for the specified key.
|
143
|
+
#
|
144
|
+
def put_if_absent(collection, key, body)
|
145
|
+
put collection, key, body, false
|
146
|
+
end
|
147
|
+
|
148
|
+
# call-seq:
|
149
|
+
# client.delete(collection_name, key) -> response
|
150
|
+
# client.delete(collection_name, key, ref) -> response
|
151
|
+
#
|
152
|
+
# Deletes the value of the specified key. Historical values for given refs are still available.
|
153
|
+
#
|
154
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
155
|
+
# +key+:: a String or Symbol representing the key for the value.
|
156
|
+
# +ref+:: if provided, used as 'If-Match', will only delete the key if the current value is the provided ref.
|
157
|
+
#
|
158
|
+
def delete(collection, key, ref=nil)
|
159
|
+
headers = {}
|
160
|
+
headers['If-Match'] = format_ref(ref) if ref
|
161
|
+
send_request :delete, [collection, key], { headers: headers }
|
162
|
+
end
|
163
|
+
|
164
|
+
# call-seq:
|
165
|
+
# client.purge(collection_name, key) -> response
|
166
|
+
#
|
167
|
+
# Deletes the value for the specified key as well as all historical values. Cannot be undone.
|
168
|
+
#
|
169
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
170
|
+
# +key+:: a String or Symbol representing the key for the value.
|
171
|
+
#
|
172
|
+
def purge(collection, key)
|
173
|
+
send_request :delete, [collection, key], { query: { purge: true } }
|
174
|
+
end
|
175
|
+
|
176
|
+
# -------------------------------------------------------------------------
|
177
|
+
# Events
|
178
|
+
|
179
|
+
# call-seq:
|
180
|
+
# client.get_event(collection_name, key, event_type, timestamp, ordinal) -> response
|
181
|
+
#
|
182
|
+
# Gets the event for the specified arguments.
|
183
|
+
#
|
184
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
185
|
+
# +key+:: a String or Symbol representing the key for the value.
|
186
|
+
# +event_type+:: a String or Symbol representing the category for the event.
|
187
|
+
# +timestamp+:: an Integer or String representing a time.
|
188
|
+
# - Integers are Milliseconds since Unix Epoch.
|
189
|
+
# - Strings must be formatted as per http://orchestrate.io/docs/api/#events/timestamps
|
190
|
+
# - A future version will support ruby Time objects.
|
191
|
+
# +ordinal+:: an Integer representing the order of the event for this timestamp.
|
192
|
+
#
|
193
|
+
def get_event(collection, key, event_type, timestamp, ordinal)
|
194
|
+
send_request :get, [collection, key, 'events', event_type, timestamp, ordinal]
|
195
|
+
end
|
196
|
+
|
197
|
+
# call-seq:
|
198
|
+
# client.post_event(collection_name, key, event_type) -> response
|
199
|
+
# client.post_event(collection_name, key, event_type, timestamp) -> response
|
200
|
+
#
|
201
|
+
# Creates an event.
|
202
|
+
#
|
203
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
204
|
+
# +key+:: a String or Symbol representing the key for the value.
|
205
|
+
# +event_type+:: a String or Symbol representing the category for the event.
|
206
|
+
# +body+:: a Hash object representing the value for the event.
|
207
|
+
# +timestamp+:: an Integer or String representing a time.
|
208
|
+
# - nil - Timestamp value will be created by Orchestrate.
|
209
|
+
# - Integers are Milliseconds since Unix Epoch.
|
210
|
+
# - Strings must be formatted as per http://orchestrate.io/docs/api/#events/timestamps
|
211
|
+
# - A future version will support ruby Time objects.
|
212
|
+
#
|
213
|
+
def post_event(collection, key, event_type, body, timestamp=nil)
|
214
|
+
path = [collection, key, 'events', event_type, timestamp].compact
|
215
|
+
send_request :post, path, { body: body }
|
216
|
+
end
|
217
|
+
|
218
|
+
# call-seq:
|
219
|
+
# client.put_event(collection_name, key, event_type, timestamp, ordinal, body) -> response
|
220
|
+
# client.put_event(collection_name, key, event_type, timestamp, ordinal, body, ref) -> response
|
221
|
+
#
|
222
|
+
# Puts the event for the specified arguments.
|
223
|
+
#
|
224
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
225
|
+
# +key+:: a String or Symbol representing the key for the value.
|
226
|
+
# +event_type+:: a String or Symbol representing the category for the event.
|
227
|
+
# +timestamp+:: an Integer or String representing a time.
|
228
|
+
# - Integers are Milliseconds since Unix Epoch.
|
229
|
+
# - Strings must be formatted as per http://orchestrate.io/docs/api/#events/timestamps
|
230
|
+
# - A future version will support ruby Time objects.
|
231
|
+
# +ordinal+:: an Integer representing the order of the event for this timestamp.
|
232
|
+
# +body+:: a Hash object representing the value for the event.
|
233
|
+
# +ref+::
|
234
|
+
# - +nil+ - The event will update regardless.
|
235
|
+
# - String - used as 'If-Match'. The event will only update if the event's current value matches this ref.
|
236
|
+
#
|
237
|
+
def put_event(collection, key, event_type, timestamp, ordinal, body, ref=nil)
|
238
|
+
path = [collection, key, 'events', event_type, timestamp, ordinal]
|
239
|
+
headers = {}
|
240
|
+
headers['If-Match'] = format_ref(ref) if ref
|
241
|
+
send_request :put, path, { body: body, headers: headers }
|
242
|
+
end
|
243
|
+
|
244
|
+
# call-seq:
|
245
|
+
# client.purge_event(collection, key, event_type, timestamp, ordinal) -> response
|
246
|
+
# client.purge_event(collection, key, event_type, timestamp, ordinal, ref) -> response
|
247
|
+
#
|
248
|
+
# Deletes the event for the specified arguments.
|
249
|
+
#
|
250
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
251
|
+
# +key+:: a String or Symbol representing the key for the value.
|
252
|
+
# +event_type+:: a String or Symbol representing the category for the event.
|
253
|
+
# +timestamp+:: an Integer or String representing a time.
|
254
|
+
# - Integers are Milliseconds since Unix Epoch.
|
255
|
+
# - Strings must be formatted as per http://orchestrate.io/docs/api/#events/timestamps
|
256
|
+
# - A future version will support ruby Time objects.
|
257
|
+
# +ordinal+:: an Integer representing the order of the event for this timestamp.
|
258
|
+
# +ref+::
|
259
|
+
# - +nil+ - The event will be deleted regardless.
|
260
|
+
# - String - used as 'If-Match'. The event will only be deleted if the event's current value matches this ref.
|
261
|
+
#
|
262
|
+
def purge_event(collection, key, event_type, timestamp, ordinal, ref=nil)
|
263
|
+
path = [collection, key, 'events', event_type, timestamp, ordinal]
|
264
|
+
headers = {}
|
265
|
+
headers['If-Match'] = format_ref(ref) if ref
|
266
|
+
send_request :delete, path, { query: { purge: true }, headers: headers }
|
267
|
+
end
|
268
|
+
|
269
|
+
# call-seq:
|
270
|
+
# client.list_events(collection_name, key, event_type) -> response
|
271
|
+
# client.list_events(collection_name, key, event_type, parameters = {}) -> response
|
272
|
+
#
|
273
|
+
# Puts the event for the specified arguments.
|
274
|
+
#
|
275
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
276
|
+
# +key+:: a String or Symbol representing the key for the value.
|
277
|
+
# +event_type+:: a String or Symbol representing the category for the event.
|
278
|
+
# +parameters+::
|
279
|
+
# - +:limit+ - integer, number of results to return. Defaults to 10, Max 100.
|
280
|
+
# - +:start+ - Integer/String representing the inclusive start to a range.
|
281
|
+
# - +:after+ - Integer/String representing the exclusive start to a range.
|
282
|
+
# - +:before+ - Integer/String representing the exclusive end to a range.
|
283
|
+
# - +:end+ - Integer/String representing the inclusive end to a range.
|
284
|
+
#
|
285
|
+
# Range parameters are formatted as ":timestamp/:ordinal":
|
286
|
+
# +timestamp+:: an Integer or String representing a time.
|
287
|
+
# - Integers are Milliseconds since Unix Epoch.
|
288
|
+
# - Strings must be formatted as per http://orchestrate.io/docs/api/#events/timestamps
|
289
|
+
# - A future version will support ruby Time objects.
|
290
|
+
# +ordinal+:: is optional.
|
291
|
+
#
|
292
|
+
def list_events(collection, key, event_type, parameters={})
|
293
|
+
Orchestrate::Helpers.range_keys!('event', parameters)
|
294
|
+
send_request :get, [collection, key, 'events', event_type], { query: parameters }
|
295
|
+
end
|
296
|
+
|
297
|
+
# -------------------------------------------------------------------------
|
298
|
+
# Graph
|
299
|
+
|
300
|
+
# call-seq:
|
301
|
+
# client.get_relations(collection_name, key, *kinds) -> response
|
302
|
+
#
|
303
|
+
# Returns the relation's collection, key and ref values.
|
304
|
+
#
|
305
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
306
|
+
# +key+:: a String or Symbol representing the key for the value.
|
307
|
+
# +kinds+:: one or more String or Symbol values representing the relations and depth to walk.
|
308
|
+
#
|
309
|
+
def get_relations(collection, key, *kinds)
|
310
|
+
path = [collection, key, 'relations'].concat(kinds)
|
311
|
+
send_request :get, path
|
312
|
+
end
|
313
|
+
|
314
|
+
# call-seq:
|
315
|
+
# client.put_relation(collection_name, key, kind, to_collection_name, to_key) -> response
|
316
|
+
#
|
317
|
+
# Stores a relationship between two Key/Value items. They do not need to be in the same collection.
|
318
|
+
#
|
319
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
320
|
+
# +key+:: a String or Symbol representing the key for the value.
|
321
|
+
# +kind+:: a String or Symbol value representing the relation type.
|
322
|
+
# +to_collection_name+:: a String or Symbol representing the name of the collection the related item belongs.
|
323
|
+
# +to_key+:: a String or Symbol representing the key for the related item.
|
324
|
+
#
|
325
|
+
def put_relation(collection, key, kind, to_collection, to_key)
|
326
|
+
send_request :put, [collection, key, 'relation', kind, to_collection, to_key]
|
327
|
+
end
|
328
|
+
|
329
|
+
# call-seq:
|
330
|
+
# client.delete_relation(collection_name, key, kind, to_collection, to_key) -> response
|
331
|
+
#
|
332
|
+
# Deletes a relationship between two Key/Value items.
|
333
|
+
#
|
334
|
+
# +collection_name+:: a String or Symbol representing the name of the collection.
|
335
|
+
# +key+:: a String or Symbol representing the key for the value.
|
336
|
+
# +kind+:: a String or Symbol value representing the relation type.
|
337
|
+
# +to_collection_name+:: a String or Symbol representing the name of the collection the related item belongs.
|
338
|
+
# +to_key+:: a String or Symbol representing the key for the related item.
|
339
|
+
#
|
340
|
+
def delete_relation(collection, key, kind, to_collection, to_key)
|
341
|
+
path = [collection, key, 'relation', kind, to_collection, to_key]
|
342
|
+
send_request :delete, path, { query: {purge: true} }
|
343
|
+
end
|
344
|
+
|
345
|
+
# call-seq:
|
346
|
+
# client.in_parallel {|responses| block } -> Hash
|
347
|
+
#
|
348
|
+
# Performs any requests generated inside the block in parallel. If the
|
349
|
+
# client isn't using a Faraday adapter that supports parallelization, will
|
350
|
+
# output a warning to STDERR.
|
351
|
+
#
|
352
|
+
# Example:
|
353
|
+
# responses = client.in_parallel do |r|
|
354
|
+
# r[:some_items] = client.list(:site_globals)
|
355
|
+
# r[:user] = client.get(:users, current_user_key)
|
356
|
+
# r[:user_feed] = client.list_events(:users, current_user_key, :notices)
|
357
|
+
# end
|
358
|
+
#
|
359
|
+
def in_parallel(&block)
|
360
|
+
accumulator = {}
|
361
|
+
http.in_parallel do
|
362
|
+
block.call(accumulator)
|
363
|
+
end
|
364
|
+
accumulator
|
365
|
+
end
|
366
|
+
|
367
|
+
# call-seq:
|
368
|
+
# client.send_request(method, url, opts={}) -> response
|
369
|
+
#
|
370
|
+
# Performs the HTTP request against the API and returns a Faraday::Response
|
371
|
+
#
|
372
|
+
# +method+ - the HTTP method, one of [ :get, :post, :put, :delete ]
|
373
|
+
# +url+ - an Array of segments to be joined with '/'
|
374
|
+
# +opts+
|
375
|
+
# - +:query+ - a Hash for the request query string
|
376
|
+
# - +:body+ - a Hash for the :put or :post request body
|
377
|
+
# - +:headers+ - a Hash the request headers
|
378
|
+
#
|
379
|
+
def send_request(method, url, opts={})
|
380
|
+
url = "/v0/#{url.join('/')}"
|
381
|
+
query_string = opts.fetch(:query, {})
|
382
|
+
body = opts.fetch(:body, '')
|
383
|
+
headers = opts.fetch(:headers, {})
|
384
|
+
headers['User-Agent'] = "ruby/orchestrate/#{Orchestrate::VERSION}"
|
385
|
+
headers['Accept'] = 'application/json' if method == :get
|
386
|
+
|
387
|
+
http.send(method) do |request|
|
388
|
+
config.logger.debug "Performing #{method.to_s.upcase} request to \"#{url}\""
|
389
|
+
request.url url, query_string
|
390
|
+
if [:put, :post].include?(method)
|
391
|
+
headers['Content-Type'] = 'application/json'
|
392
|
+
request.body = body.to_json
|
393
|
+
end
|
394
|
+
headers.each {|header, value| request[header] = value }
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# ------------------------------------------------------------------------
|
399
|
+
|
400
|
+
private
|
401
|
+
|
402
|
+
# Formats the provided 'ref' to be quoted per API specification. If
|
403
|
+
# already quoted, does not add additional quotes.
|
404
|
+
def format_ref(ref)
|
405
|
+
"\"#{ref.gsub(/"/,'')}\""
|
406
|
+
end
|
407
|
+
|
408
|
+
end
|
409
|
+
|
410
|
+
end
|