elastomer-client 0.3.1

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +4 -0
  5. data/Gemfile +5 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +108 -0
  8. data/Rakefile +9 -0
  9. data/docs/notifications.md +71 -0
  10. data/elastomer-client.gemspec +30 -0
  11. data/lib/elastomer/client.rb +307 -0
  12. data/lib/elastomer/client/bulk.rb +257 -0
  13. data/lib/elastomer/client/cluster.rb +208 -0
  14. data/lib/elastomer/client/docs.rb +432 -0
  15. data/lib/elastomer/client/errors.rb +51 -0
  16. data/lib/elastomer/client/index.rb +407 -0
  17. data/lib/elastomer/client/multi_search.rb +115 -0
  18. data/lib/elastomer/client/nodes.rb +87 -0
  19. data/lib/elastomer/client/scan.rb +161 -0
  20. data/lib/elastomer/client/template.rb +85 -0
  21. data/lib/elastomer/client/warmer.rb +96 -0
  22. data/lib/elastomer/core_ext/time.rb +7 -0
  23. data/lib/elastomer/middleware/encode_json.rb +51 -0
  24. data/lib/elastomer/middleware/opaque_id.rb +69 -0
  25. data/lib/elastomer/middleware/parse_json.rb +39 -0
  26. data/lib/elastomer/notifications.rb +83 -0
  27. data/lib/elastomer/version.rb +7 -0
  28. data/script/bootstrap +16 -0
  29. data/script/cibuild +28 -0
  30. data/script/console +9 -0
  31. data/script/testsuite +10 -0
  32. data/test/assertions.rb +74 -0
  33. data/test/client/bulk_test.rb +226 -0
  34. data/test/client/cluster_test.rb +113 -0
  35. data/test/client/docs_test.rb +394 -0
  36. data/test/client/index_test.rb +244 -0
  37. data/test/client/multi_search_test.rb +129 -0
  38. data/test/client/nodes_test.rb +35 -0
  39. data/test/client/scan_test.rb +84 -0
  40. data/test/client/stubbed_client_tests.rb +40 -0
  41. data/test/client/template_test.rb +33 -0
  42. data/test/client/warmer_test.rb +56 -0
  43. data/test/client_test.rb +86 -0
  44. data/test/core_ext/time_test.rb +46 -0
  45. data/test/middleware/encode_json_test.rb +53 -0
  46. data/test/middleware/opaque_id_test.rb +39 -0
  47. data/test/middleware/parse_json_test.rb +54 -0
  48. data/test/test_helper.rb +94 -0
  49. metadata +210 -0
@@ -0,0 +1,87 @@
1
+
2
+ module Elastomer
3
+ class Client
4
+
5
+ # Provides access to node-level API commands.
6
+ #
7
+ # node_id - The node ID as a String or an Array of node IDs
8
+ #
9
+ # Returns a Nodes instance.
10
+ def nodes( node_id = '_all' )
11
+ Nodes.new self, node_id
12
+ end
13
+
14
+
15
+ class Nodes
16
+ # Create a new nodes client for making API requests that pertain to
17
+ # the health and management individual nodes.
18
+ #
19
+ # client - Elastomer::Client used for HTTP requests to the server
20
+ # node_id - The node ID as a String or an Array of node IDs
21
+ #
22
+ def initialize( client, node_id )
23
+ @client = client
24
+ @node_id = node_id
25
+ end
26
+
27
+ attr_reader :client, :node_id
28
+
29
+ # Retrieve one or more (or all) of the cluster nodes information.
30
+ # See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-info/
31
+ #
32
+ # params - Parameters Hash
33
+ #
34
+ # Returns the response as a Hash
35
+ def info( params = {} )
36
+ response = client.get '/_nodes{/node_id}', update_params(params, :action => 'nodes.info')
37
+ response.body
38
+ end
39
+
40
+ # Retrieve one or more (or all) of the cluster nodes statistics.
41
+ # See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-stats/
42
+ #
43
+ # params - Parameters Hash
44
+ #
45
+ # Returns the response as a Hash
46
+ def stats( params = {} )
47
+ response = client.get '/_nodes{/node_id}/stats', update_params(params, :action => 'nodes.stats')
48
+ response.body
49
+ end
50
+
51
+ # Get the current hot threads on each node in the cluster.
52
+ # See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-hot-threads/
53
+ #
54
+ # params - Parameters Hash
55
+ #
56
+ # Returns the response as a Hash
57
+ def hot_threads( params = {} )
58
+ response = client.get '/_nodes{/node_id}/hot_threads', update_params(params, :action => 'nodes.hot_threads')
59
+ response.body
60
+ end
61
+
62
+ # Shutdown one or more nodes in the cluster.
63
+ # See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown/
64
+ #
65
+ # params - Parameters Hash
66
+ #
67
+ # Returns the response as a Hash
68
+ def shutdown( params = {} )
69
+ response = client.post '/_cluster/nodes{/node_id}/_shutdown', update_params(params, :action => 'nodes.shutdown')
70
+ response.body
71
+ end
72
+
73
+ # Internal: Add default parameters to the `params` Hash and then apply
74
+ # `overrides` to the params if any are given.
75
+ #
76
+ # params - Parameters Hash
77
+ # overrides - Optional parameter overrides as a Hash
78
+ #
79
+ # Returns a new params Hash.
80
+ def update_params( params, overrides = nil )
81
+ h = { :node_id => node_id }.update params
82
+ h.update overrides unless overrides.nil?
83
+ h
84
+ end
85
+ end # Nodes
86
+ end # Client
87
+ end # Elastomer
@@ -0,0 +1,161 @@
1
+ module Elastomer
2
+ class Client
3
+
4
+ # Create a new Scan instance for scrolling all results from a `query`.
5
+ #
6
+ # query - The query to scan as a Hash or a JSON encoded String
7
+ # opts - Options Hash
8
+ # :index - the name of the index to search
9
+ # :type - the document type to search
10
+ # :scroll - the keep alive time of the scrolling request (5 minutes by default)
11
+ # :size - the number of documents per shard to fetch per scroll
12
+ #
13
+ # Examples
14
+ #
15
+ # scan = client.scan('{"query":{"match_all":{}}}', :index => 'test')
16
+ # scan.each_document do |document|
17
+ # document['_id']
18
+ # document['_source']
19
+ # end
20
+ #
21
+ # Returns a new Scan instance
22
+ def scan( query, opts = {} )
23
+ Scan.new self, query, opts
24
+ end
25
+
26
+ # Continue scrolling a scan query.
27
+ # See http://www.elasticsearch.org/guide/reference/api/search/scroll/
28
+ #
29
+ # scroll_id - The current scroll ID as a String
30
+ # scroll - The keep alive time of the scrolling request (5 minutes by default)
31
+ #
32
+ # Examples
33
+ #
34
+ # scroll_id = client.scan('{"query":{"match_all":{}}}', :index => 'test').scroll_id
35
+ #
36
+ # h = client.scroll scroll_id # scroll to get the next set of results
37
+ # scroll_id = h['_scroll_id'] # and store the scroll_id to use later
38
+ #
39
+ # h = client.scroll scroll_id # scroll again to get the next set of results
40
+ # scroll_id = h['_scroll_id'] # and store the scroll_id to use later
41
+ #
42
+ # # repeat until the results are empty
43
+ #
44
+ # Returns the response body as a Hash.
45
+ def scroll( scroll_id, scroll = '5m' )
46
+ response = get '/_search/scroll', :body => scroll_id, :scroll => scroll, :action => 'search.scroll'
47
+ response.body
48
+ end
49
+
50
+
51
+ class Scan
52
+ # Create a new scan client that can be used to iterate over all the
53
+ # documents returned by the `query`.
54
+ #
55
+ # See http://www.elasticsearch.org/guide/reference/api/search/scroll/
56
+ # and the "Scan" section of http://www.elasticsearch.org/guide/reference/api/search/search-type/
57
+ #
58
+ # client - Elastomer::Client used for HTTP requests to the server
59
+ # query - The query to scan as a Hash or a JSON encoded String
60
+ # opts - Options Hash
61
+ # :index - the name of the index to search
62
+ # :type - the document type to search
63
+ # :scroll - the keep alive time of the scrolling request (5 minutes by default)
64
+ # :size - the number of documents per shard to fetch per scroll
65
+ #
66
+ # Examples
67
+ #
68
+ # scan = Scan.new(client, {:query => {:match_all => {}}}, :index => 'test-1')
69
+ # scan.each_document { |doc|
70
+ # doc['_id']
71
+ # doc['_source']
72
+ # }
73
+ #
74
+ def initialize( client, query, opts = {} )
75
+ @client = client
76
+ @query = query
77
+
78
+ @index = opts.fetch(:index, nil)
79
+ @type = opts.fetch(:type, nil)
80
+ @scroll = opts.fetch(:scroll, '5m')
81
+ @size = opts.fetch(:size, 50)
82
+
83
+ @offset = 0
84
+ end
85
+
86
+ attr_reader :client, :query, :index, :type, :scroll, :size
87
+
88
+ # Iterate over all the search results from the scan query.
89
+ #
90
+ # block - The block will be called for each set of matching documents
91
+ # returned from executing the scan query.
92
+ #
93
+ # Yields a hits Hash containing the 'total' number of hits, current
94
+ # 'offset' into that total, and the Array of 'hits' document Hashes.
95
+ #
96
+ # Examples
97
+ #
98
+ # scan.each do |hits|
99
+ # hits['total']
100
+ # hits['offset']
101
+ # hits['hits'].each { |document| ... }
102
+ # end
103
+ #
104
+ # Returns this Scan instance.
105
+ def each
106
+ loop do
107
+ body = client.scroll scroll_id, scroll
108
+ @scroll_id = body['_scroll_id']
109
+
110
+ hits = body['hits']
111
+ break if hits['hits'].empty?
112
+
113
+ hits['offset'] = @offset
114
+ @offset += hits['hits'].length
115
+
116
+ yield hits
117
+ end
118
+
119
+ self
120
+ end
121
+
122
+ # Iterate over each document from the scan query. This method is just a
123
+ # convenience wrapper around the `each` method; it iterates the Array of
124
+ # documents and passes them one by one to the block.
125
+ #
126
+ # block - The block will be called for each document returned from
127
+ # executing the scan query.
128
+ #
129
+ # Yields a document Hash.
130
+ #
131
+ # Examples
132
+ #
133
+ # scan.each_document do |document|
134
+ # document['_id']
135
+ # document['_source']
136
+ # end
137
+ #
138
+ # Returns this Scan instance.
139
+ def each_document( &block )
140
+ each { |hits| hits['hits'].each(&block) }
141
+ end
142
+
143
+ # Internal: Returns the current scroll ID as a String.
144
+ def scroll_id
145
+ return @scroll_id if defined? @scroll_id
146
+
147
+ response = client.get '{/index}{/type}/_search',
148
+ :action => 'search.scan',
149
+ :search_type => 'scan',
150
+ :scroll => scroll,
151
+ :size => size,
152
+ :index => index,
153
+ :type => type,
154
+ :body => query
155
+
156
+ @scroll_id = response.body['_scroll_id']
157
+ end
158
+
159
+ end # Scan
160
+ end # Client
161
+ end # Elastomer
@@ -0,0 +1,85 @@
1
+
2
+ module Elastomer
3
+ class Client
4
+
5
+ # Returns a Template instance.
6
+ def template( name )
7
+ Template.new self, name
8
+ end
9
+
10
+
11
+ class Template
12
+
13
+ # Create a new template client for making API requests that pertain to
14
+ # template management.
15
+ #
16
+ # client - Elastomer::Client used for HTTP requests to the server
17
+ # name - The name of the template as a String
18
+ #
19
+ def initialize( client, name )
20
+ @client = client
21
+ @name = name
22
+ end
23
+
24
+ attr_reader :client, :name
25
+
26
+ # Returns true if the template already exists on the cluster.
27
+ def exists?
28
+ client.cluster.templates.key? name
29
+ end
30
+ alias :exist? :exists?
31
+
32
+ # Get the template from the cluster.
33
+ # See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/
34
+ #
35
+ # params - Parameters Hash
36
+ #
37
+ # Returns the response body as a Hash
38
+ def get( params = {} )
39
+ response = client.get '/_template/{template}', update_params(params, :action => 'template.get')
40
+ response.body
41
+ end
42
+
43
+ # Create the template on the cluster.
44
+ # See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/
45
+ #
46
+ # template - The template as a Hash or a JSON encoded String
47
+ # params - Parameters Hash
48
+ #
49
+ # Returns the response body as a Hash
50
+ def create( template, params = {} )
51
+ response = client.put '/_template/{template}', update_params(params, :body => template, :action => 'template.create')
52
+ response.body
53
+ end
54
+
55
+ # Delete the template from the cluster.
56
+ # See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/
57
+ #
58
+ # params - Parameters Hash
59
+ #
60
+ # Returns the response body as a Hash
61
+ def delete( params = {} )
62
+ response = client.delete '/_template/{template}', update_params(params, :action => 'template.delete')
63
+ response.body
64
+ end
65
+
66
+ # Internal: Add default parameters to the `params` Hash and then apply
67
+ # `overrides` to the params if any are given.
68
+ #
69
+ # params - Parameters Hash
70
+ # overrides - Optional parameter overrides as a Hash
71
+ #
72
+ # Returns a new params Hash.
73
+ def update_params( params, overrides = nil )
74
+ h = defaults.update params
75
+ h.update overrides unless overrides.nil?
76
+ h
77
+ end
78
+
79
+ # Internal: Returns a Hash containing default parameters.
80
+ def defaults
81
+ { :template => name }
82
+ end
83
+ end # Template
84
+ end # Client
85
+ end # Elastomer
@@ -0,0 +1,96 @@
1
+ module Elastomer
2
+ class Client
3
+
4
+ # Provides access to warmer API commands.
5
+ # See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
6
+ #
7
+ # index_name - The name of the index as a String
8
+ # warmer_name - The name of the warmer as a String
9
+ #
10
+ # Returns a Warmer instance.
11
+ def warmer(index_name, warmer_name)
12
+ Warmer.new(self, index_name, warmer_name)
13
+ end
14
+
15
+ class Warmer
16
+
17
+ # Create a new Warmer helper for making warmer API requests.
18
+ #
19
+ # client - Elastomer::Client used for HTTP requests to the server
20
+ # index_name - The name of the index as a String
21
+ # name - The name of the warmer as a String
22
+ def initialize(client, index_name, name)
23
+ @client = client
24
+ @index_name = @client.assert_param_presence(index_name, 'index name')
25
+ @name = @client.assert_param_presence(name, 'warmer name')
26
+ end
27
+
28
+ attr_reader :client, :index_name, :name
29
+
30
+ # Create a warmer.
31
+ # See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
32
+ #
33
+ # query - The query the warmer should run
34
+ # params - Parameters Hash
35
+ #
36
+ # Examples
37
+ #
38
+ # warmer.create(:query => {:match_all => {}})
39
+ #
40
+ # Returns the response body as a Hash
41
+ def create(query, params = {})
42
+ response = client.put '/{index}{/type}/_warmer/{warmer}', defaults.update(params.update(:body => query))
43
+ response.body
44
+ end
45
+
46
+ # Delete a warmer.
47
+ # See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
48
+ #
49
+ # params - Parameters Hash
50
+ #
51
+ # Returns the response body as a Hash
52
+ def delete(params = {})
53
+ response = client.delete '/{index}{/type}/_warmer/{warmer}', defaults.update(params)
54
+ response.body
55
+ end
56
+
57
+ # Get a warmer.
58
+ # See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
59
+ #
60
+ # params - Parameters Hash
61
+ #
62
+ # Returns the response body as a Hash
63
+ def get(params = {})
64
+ response = client.get '/{index}{/type}/_warmer/{warmer}', defaults.update(params)
65
+ response.body
66
+ end
67
+
68
+ # Check whether a warmer exists. Also aliased as exist?
69
+ #
70
+ # Since there is no native warmer exists api, this method executes
71
+ # a get and watches for an IndexWarmerMissingException error.
72
+ #
73
+ # Returns true if the warmer exists, false if not.
74
+ #COMPATIBILITY warmer response differs in ES 1.0
75
+ # ES 1.0: missing warmer returns {} with 200 status
76
+ # ES 0.90: missing warmer returns IndexWarmerMissingException error
77
+ # See https://github.com/elasticsearch/elasticsearch/issues/5155
78
+ def exists?
79
+ response = get
80
+ response != {}
81
+ rescue Elastomer::Client::Error => exception
82
+ if exception.message =~ /IndexWarmerMissingException/
83
+ false
84
+ else
85
+ raise exception
86
+ end
87
+ end
88
+ alias :exist? :exists?
89
+
90
+ # Internal: Returns a Hash containing default parameters.
91
+ def defaults
92
+ {:index => index_name, :warmer => name}
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,7 @@
1
+ require 'time'
2
+
3
+ class Time
4
+ def to_json(ignore = nil)
5
+ %Q["#{self.iso8601}"]
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ module Elastomer
2
+ module Middleware
3
+ # Request middleware that encodes the body as JSON.
4
+ #
5
+ # Processes only requests with matching Content-type or those without a type.
6
+ # If a request doesn't have a type but has a body, it sets the Content-type
7
+ # to JSON MIME-type.
8
+ #
9
+ # Doesn't try to encode bodies that already are in string form.
10
+ class EncodeJson < Faraday::Middleware
11
+ CONTENT_TYPE = 'Content-Type'.freeze
12
+ MIME_TYPE = 'application/json'.freeze
13
+
14
+ def call(env)
15
+ match_content_type(env) do |data|
16
+ env[:body] = encode data
17
+ end
18
+ @app.call env
19
+ end
20
+
21
+ def encode(data)
22
+ MultiJson.dump data
23
+ end
24
+
25
+ def match_content_type(env)
26
+ if process_request?(env)
27
+ env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
28
+ yield env[:body] unless env[:body].respond_to?(:to_str)
29
+ end
30
+ end
31
+
32
+ def process_request?(env)
33
+ type = request_type(env)
34
+ has_body?(env) and (type.empty? or type == MIME_TYPE)
35
+ end
36
+
37
+ def has_body?(env)
38
+ body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
39
+ end
40
+
41
+ def request_type(env)
42
+ type = env[:request_headers][CONTENT_TYPE].to_s
43
+ type = type.split(';', 2).first if type.index(';')
44
+ type
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Faraday::Request.register_middleware \
51
+ :encode_json => ::Elastomer::Middleware::EncodeJson