eson-core 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/LICENSE.md +20 -0
  2. data/README.md +5 -0
  3. data/Rakefile +35 -0
  4. data/eson-core.gemspec +23 -0
  5. data/lib/eson/api.rb +63 -0
  6. data/lib/eson/chainable.rb +20 -0
  7. data/lib/eson/client.rb +253 -0
  8. data/lib/eson/error.rb +14 -0
  9. data/lib/eson/request.rb +113 -0
  10. data/lib/eson/shared/cluster/health.rb +16 -0
  11. data/lib/eson/shared/cluster/nodes.rb +15 -0
  12. data/lib/eson/shared/cluster/shutdown.rb +20 -0
  13. data/lib/eson/shared/cluster/state.rb +17 -0
  14. data/lib/eson/shared/cluster/stats.rb +15 -0
  15. data/lib/eson/shared/core/bulk.rb +26 -0
  16. data/lib/eson/shared/core/count.rb +63 -0
  17. data/lib/eson/shared/core/delete.rb +26 -0
  18. data/lib/eson/shared/core/delete_by_query.rb +50 -0
  19. data/lib/eson/shared/core/get.rb +19 -0
  20. data/lib/eson/shared/core/index.rb +33 -0
  21. data/lib/eson/shared/core/mget.rb +16 -0
  22. data/lib/eson/shared/core/more_like_this.rb +52 -0
  23. data/lib/eson/shared/core/msearch.rb +37 -0
  24. data/lib/eson/shared/core/percolate.rb +18 -0
  25. data/lib/eson/shared/core/search.rb +62 -0
  26. data/lib/eson/shared/core/simple_search.rb +35 -0
  27. data/lib/eson/shared/indices/aliases.rb +24 -0
  28. data/lib/eson/shared/indices/analyze.rb +11 -0
  29. data/lib/eson/shared/indices/clear_cache.rb +13 -0
  30. data/lib/eson/shared/indices/close_index.rb +9 -0
  31. data/lib/eson/shared/indices/create_index.rb +13 -0
  32. data/lib/eson/shared/indices/delete_index.rb +9 -0
  33. data/lib/eson/shared/indices/delete_mapping.rb +11 -0
  34. data/lib/eson/shared/indices/delete_template.rb +9 -0
  35. data/lib/eson/shared/indices/exists.rb +9 -0
  36. data/lib/eson/shared/indices/flush.rb +11 -0
  37. data/lib/eson/shared/indices/get_mapping.rb +16 -0
  38. data/lib/eson/shared/indices/get_settings.rb +9 -0
  39. data/lib/eson/shared/indices/get_template.rb +9 -0
  40. data/lib/eson/shared/indices/open_index.rb +9 -0
  41. data/lib/eson/shared/indices/optimize.rb +15 -0
  42. data/lib/eson/shared/indices/put_mapping.rb +15 -0
  43. data/lib/eson/shared/indices/put_template.rb +10 -0
  44. data/lib/eson/shared/indices/refresh.rb +16 -0
  45. data/lib/eson/shared/indices/segments.rb +8 -0
  46. data/lib/eson/shared/indices/snapshot.rb +9 -0
  47. data/lib/eson/shared/indices/stats.rb +19 -0
  48. data/lib/eson/shared/indices/status.rb +9 -0
  49. data/lib/eson/shared/indices/update_settings.rb +12 -0
  50. data/lib/eson-core.rb +49 -0
  51. metadata +135 -0
data/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Florian Gilcher <florian.gilcher@asquera.de>, Felix Gilcher <felix.gilcher@asquera.de>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # eson-core
2
+
3
+ Core classes for implementing an ElasticSearch client.
4
+
5
+ This is a meta-gem that provides a definition of the whole ElasticSearch API (parameter values, required parameters, etc.). It also provides a client class for working with these definitions.
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'rake/testtask'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/testtask'
4
+
5
+ def gemspec
6
+ @gemspec ||= begin
7
+ file = File.expand_path("eson-core.gemspec")
8
+ ::Gem::Specification.load(file)
9
+ end
10
+ end
11
+
12
+ desc "Validates the gemspec"
13
+ task :gemspec do
14
+ gemspec.validate
15
+ end
16
+
17
+ Rake::GemPackageTask.new(gemspec) do |pkg|
18
+ pkg.gem_spec = gemspec
19
+ end
20
+
21
+ task :package => :gemspec
22
+
23
+ Rake::TestTask.new(:test) do |test|
24
+ if 'jruby' == RUBY_ENGINE
25
+ test.pattern = 'test/**/*_test.rb'
26
+ else
27
+ test.pattern = 'test/{http,search}/*_test.rb'
28
+ end
29
+
30
+ test.verbose = true
31
+ end
32
+
33
+ task :seed do
34
+ require './test/seeds/seeds'
35
+ end
data/eson-core.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "eson-core"
6
+ s.version = "0.7.0" #Echolon::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Florian Gilcher"]
9
+ s.email = ["florian.gilcher@asquera.de"]
10
+ s.homepage = ""
11
+ s.summary = %q{A modular client for ElasticSearch - Core components}
12
+ s.description = %q{A modular client for ElasticSearch. It provides
13
+ an implementation of the Query language as well as multiple client implementations
14
+ for HTTP and native access.}
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ #s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "multi_json"
22
+ s.add_development_dependency "elasticsearch-node"
23
+ end
data/lib/eson/api.rb ADDED
@@ -0,0 +1,63 @@
1
+ module Eson
2
+ module API
3
+ include Chainable
4
+
5
+ def parameters(*params)
6
+ chainable do
7
+ define_method :parameters do
8
+ super() + params
9
+ end
10
+
11
+ params.each do |p|
12
+ attr_accessor p
13
+ end
14
+ end
15
+ end
16
+
17
+ # Designates the name of the parameter that will be used as the
18
+ # body of the request. Use only if the API has such a parameter (e.g. Search).
19
+ # You still have to list this parameter.
20
+ #
21
+ # If multiple parameters are given, they will act as the keys in the sent
22
+ # JSON object.
23
+ #
24
+ # @example source_param call
25
+ # source_param :settings, :mappings
26
+ # @example result
27
+ # {
28
+ # "settings" : {...},
29
+ # "mappings" : {...}
30
+ # }
31
+ def source_param(*params)
32
+ if params.length == 1
33
+ params = params.first
34
+ end
35
+
36
+ define_method :source_param do
37
+ params
38
+ end
39
+ end
40
+
41
+ def multi_index(bool)
42
+ define_method :multi_index do
43
+ bool
44
+ end
45
+ end
46
+
47
+ def multi_types(bool)
48
+ define_method :multi_types do
49
+ bool
50
+ end
51
+ end
52
+
53
+ def no_indices(bool)
54
+ define_method :no_indices do
55
+ bool
56
+ end
57
+ end
58
+
59
+ def register(mod)
60
+ include(mod)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ # code from the datamapper project. See http://datamapper.org
2
+
3
+ module Eson
4
+ module Chainable
5
+
6
+ # @api private
7
+ def chainable(&block)
8
+ mod = Module.new(&block)
9
+ include mod
10
+ mod
11
+ end
12
+
13
+ # @api private
14
+ def extendable(&block)
15
+ mod = Module.new(&block)
16
+ extend mod
17
+ mod
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,253 @@
1
+ module Eson
2
+ class Client
3
+ attr_accessor :server
4
+ attr_accessor :index_name
5
+ attr_accessor :default_index
6
+ attr_accessor :protocol
7
+ attr_accessor :plugins
8
+ attr_accessor :opts
9
+ attr_accessor :auto_call
10
+
11
+ DEFAULT_OPTS = {
12
+ :server => 'http://127.0.0.1:9200',
13
+ :plugins => [],
14
+ :logger => nil,
15
+ :default_index => "default"
16
+ }
17
+
18
+ # TODO: allow multiple servers and pick them at random
19
+ def initialize(opts = {})
20
+ opts = DEFAULT_OPTS.merge(opts)
21
+
22
+ self.server = opts[:server]
23
+ self.default_index = opts[:default_index]
24
+ self.protocol = opts[:protocol] || Eson::HTTP
25
+ self.plugins = opts[:plugins]
26
+ self.logger = opts[:logger]
27
+ if opts[:auto_call].nil?
28
+ self.auto_call = true
29
+ else
30
+ self.auto_call = opts[:auto_call]
31
+ end
32
+ self.opts = opts
33
+ end
34
+
35
+ def node
36
+ self.server
37
+ end
38
+
39
+ def logger=(logger)
40
+ protocol.logger = logger
41
+ end
42
+
43
+ def logger(logger)
44
+ protocol.logger
45
+ end
46
+
47
+ def auth?
48
+ !!opts[:auth]
49
+ end
50
+
51
+ def auth
52
+ opts[:auth]
53
+ end
54
+
55
+ def index_name
56
+ @index_name || default_index
57
+ end
58
+
59
+ def [](index_name)
60
+ c = self.clone
61
+ c.index_name = index_name
62
+ c
63
+ end
64
+
65
+ def index(args = {}, immediate = auto_call)
66
+ request(protocol::Index, args, immediate)
67
+ end
68
+
69
+ def delete(args = {}, immediate = auto_call)
70
+ request(protocol::Delete, args, immediate)
71
+ end
72
+
73
+ def get(args = {})
74
+ request(protocol::Get, args)
75
+ end
76
+
77
+ def mget(args = {})
78
+ request(protocol::MultiGet, args)
79
+ end
80
+
81
+ def search(args = {}, immediate = auto_call, &block)
82
+ request(protocol::Search, args, immediate, &block)
83
+ end
84
+ alias :query :search
85
+
86
+ def simple_search(args = {})
87
+ request(protocol::SimpleSearch, args)
88
+ end
89
+
90
+ def count(args = {})
91
+ request(protocol::Count, args)
92
+ end
93
+
94
+ def percolate(args = {}, &block)
95
+ request(protocol::Percolate, args, &block)
96
+ end
97
+
98
+ def bulk(args = {}, &block)
99
+ if block_given?
100
+ request(protocol::Bulk, args, &block)
101
+ else
102
+ request(protocol::Bulk, args, false)
103
+ end
104
+ end
105
+
106
+ def msearch(args = {}, &block)
107
+ if block_given?
108
+ request(protocol::MultiSearch, args, &block)
109
+ else
110
+ request(protocol::MultiSearch, args, false)
111
+ end
112
+ end
113
+
114
+ def delete_by_query(args = {}, &block)
115
+ request(protocol::DeleteByQuery, args, &block)
116
+ end
117
+
118
+ def more_like_this(args = {})
119
+ request(protocol::MoreLikeThis, args)
120
+ end
121
+
122
+ def health(args = {})
123
+ request(protocol::Health, args)
124
+ end
125
+
126
+ def state(args = {})
127
+ request(protocol::State, args)
128
+ end
129
+
130
+ def stats(args = {})
131
+ request(protocol::Stats, args)
132
+ end
133
+
134
+ def nodes(args = {})
135
+ request(protocol::Nodes, args)
136
+ end
137
+
138
+ def shutdown(args = {})
139
+ request(protocol::Shutdown, args)
140
+ end
141
+
142
+ def aliases(args = {}, &block)
143
+ request(protocol::Aliases, args, &block)
144
+ end
145
+
146
+ def analyze(args = {})
147
+ request(protocol::Analyze, args)
148
+ end
149
+
150
+ def clear_cache(args = {})
151
+ request(protocol::ClearCache, args)
152
+ end
153
+
154
+ def close_index(args = {})
155
+ request(protocol::CloseIndex, args)
156
+ end
157
+
158
+ def open_index(args = {})
159
+ request(protocol::OpenIndex, args)
160
+ end
161
+
162
+ def create_index(args = {})
163
+ request(protocol::CreateIndex, args)
164
+ end
165
+
166
+ def delete_index(args = {})
167
+ request(protocol::DeleteIndex, args)
168
+ end
169
+
170
+ def delete_mapping(args = {})
171
+ request(protocol::DeleteMapping, args)
172
+ end
173
+
174
+ def get_mapping(args = {})
175
+ request(protocol::GetMapping, args)
176
+ end
177
+
178
+ def put_mapping(args = {})
179
+ request(protocol::PutMapping, args)
180
+ end
181
+
182
+ def put_template(args = {})
183
+ request(protocol::PutTemplate, args)
184
+ end
185
+
186
+ def get_template(args = {})
187
+ request(protocol::GetTemplate, args)
188
+ end
189
+
190
+ def delete_template(args = {})
191
+ request(protocol::DeleteTemplate, args)
192
+ end
193
+
194
+ def get_settings(args = {})
195
+ request(protocol::GetSettings, args)
196
+ end
197
+
198
+ def update_settings(args = {})
199
+ request(protocol::UpdateSettings, args)
200
+ end
201
+
202
+ def flush(args = {})
203
+ request(protocol::Flush, args)
204
+ end
205
+
206
+ def optimize(args = {})
207
+ request(protocol::Optimize, args)
208
+ end
209
+
210
+ def refresh(args = {})
211
+ request(protocol::Refresh, args)
212
+ end
213
+
214
+ def snapshot(args = {})
215
+ request(protocol::Snapshot, args)
216
+ end
217
+
218
+ def status(args = {})
219
+ request(protocol::Status, args)
220
+ end
221
+
222
+ def index_stats(args = {})
223
+ request(protocol::IndexStats, args)
224
+ end
225
+
226
+ def segments(args = {})
227
+ request(protocol::Segments, args)
228
+ end
229
+
230
+ def exists?(args = {})
231
+ request(protocol::IndexExists, args)
232
+ rescue Eson::NotFoundError
233
+ false
234
+ end
235
+
236
+ private
237
+ def request(endpoint, args, auto_call = auto_call)
238
+ r = protocol::Request.new(endpoint, plugins, self)
239
+
240
+ r.params = args
241
+
242
+ if block_given?
243
+ r.handle_block(&Proc.new)
244
+ end
245
+
246
+ if auto_call
247
+ r.call
248
+ else
249
+ r
250
+ end
251
+ end
252
+ end
253
+ end
data/lib/eson/error.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Eson
2
+ class Error < StandardError
3
+ attr_accessor :response
4
+
5
+ def initialize(msg, response)
6
+ super(msg)
7
+
8
+ self.response = response
9
+ end
10
+ end
11
+
12
+ NotFoundError = Class.new(Error)
13
+ IndexNotFoundError = Class.new(NotFoundError)
14
+ end
@@ -0,0 +1,113 @@
1
+ module Eson
2
+ class Request
3
+ attr_accessor :api, :client
4
+
5
+ attr_accessor :pretty, :source, :index, :indices, :case
6
+
7
+ def initialize(api, plugins, client)
8
+ self.api = api
9
+ self.client = client
10
+ self.extend(api)
11
+
12
+ Array(plugins).each do |p|
13
+ if pluggable?(api, p, client)
14
+ self.extend(p)
15
+ end
16
+ end
17
+ end
18
+
19
+ def handle_block
20
+ yield self
21
+ end
22
+
23
+ def params=(params)
24
+ params.each do |k,v|
25
+ begin
26
+ self.send("#{k}=", v)
27
+ rescue NoMethodError => e
28
+ raise NoMethodError, "Tried to set parameter `#{k}`, but request has no such parameter."
29
+ end
30
+ end
31
+ end
32
+
33
+ def pluggable?(api, plugin, client)
34
+ if plugin.respond_to? :plugin_for
35
+ plugin.plugin_for(client.protocol).include?(api)
36
+ else
37
+ true
38
+ end
39
+ end
40
+
41
+ def index
42
+ @index || client.index_name
43
+ end
44
+
45
+ def parameters
46
+ if self.respond_to?(:multi_index) && (multi_index == true)
47
+ [:pretty, :indices, :case]
48
+ elsif self.respond_to?(:multi_index) && (multi_index == false)
49
+ [:pretty, :index, :case]
50
+ else
51
+ [:pretty, :case]
52
+ end
53
+ end
54
+
55
+ def indices
56
+ if @indices
57
+ Array(@indices)
58
+ else
59
+ Array(self.index)
60
+ end
61
+ end
62
+
63
+ def source
64
+ @source || source_from_params
65
+ end
66
+
67
+ # TODO: woah, this needs refactoring
68
+
69
+ def source_from_params
70
+ return nil unless self.respond_to? :source_param
71
+
72
+ if Symbol === source_param
73
+ obj = self.send source_param
74
+ if (String === obj || obj.nil?)
75
+ return obj
76
+ else
77
+ return encode(obj)
78
+ end
79
+ else
80
+ pairs = source_param.map do |p|
81
+ if v = self.send(p)
82
+ [p, v]
83
+ else
84
+ nil
85
+ end
86
+ end
87
+ pairs.compact!
88
+
89
+ return nil if pairs.empty?
90
+
91
+ obj = {}
92
+
93
+ pairs.each do |p, v|
94
+ obj[p] = v
95
+ end
96
+
97
+ return encode(obj)
98
+ end
99
+ end
100
+
101
+ def encode(obj)
102
+ if obj.respond_to? :to_query_hash
103
+ obj = obj.to_query_hash
104
+ end
105
+
106
+ if obj.respond_to? :to_json
107
+ obj.to_json
108
+ else
109
+ MultiJson.encode(obj)
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,16 @@
1
+ module Eson
2
+ module Shared
3
+ module Health
4
+ extend API
5
+
6
+ multi_index true
7
+
8
+ parameters :wait_for_status,
9
+ :level,
10
+ :wait_for_relocating_shards,
11
+ :wait_for_nodes,
12
+ :timeout
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Eson
2
+ module Shared
3
+ module Nodes
4
+ extend API
5
+
6
+ multi_index false
7
+
8
+ parameters :nodes
9
+
10
+ def nodes
11
+ Array(@nodes)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module Eson
2
+ module Shared
3
+ module Shutdown
4
+ #TODO fully implement and test this
5
+ extend API
6
+
7
+ multi_index false
8
+
9
+ parameters :nodes,
10
+ :delay,
11
+ :master,
12
+ :local,
13
+ :all
14
+
15
+ def nodes
16
+ Array(@nodes)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Eson
2
+ module Shared
3
+ module State
4
+ extend API
5
+ #TODO implement filter_indices correctly
6
+
7
+ multi_index true
8
+
9
+ parameters :filter_nodes,
10
+ :filter_routing_table,
11
+ :filter_metadata,
12
+ :filter_blocks,
13
+ :filter_indices
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module Eson
2
+ module Shared
3
+ module Stats
4
+ extend API
5
+
6
+ multi_index false
7
+
8
+ parameters :nodes
9
+
10
+ def nodes
11
+ Array(@nodes)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Eson
2
+ module Shared
3
+ module Bulk
4
+ extend API
5
+
6
+ source_param :bulk
7
+ parameters :bulk
8
+
9
+ def bulk
10
+ @bulk ||= []
11
+ end
12
+
13
+ def <<(request)
14
+ bulk << request
15
+ end
16
+
17
+ def index(args, immediate = nil)
18
+ self << client.index(args, false)
19
+ end
20
+
21
+ def delete(args, immediate = nil)
22
+ self << client.delete(args, false)
23
+ end
24
+ end
25
+ end
26
+ end