elastics-client 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +28 -0
  3. data/VERSION +1 -0
  4. data/elastics-client.gemspec +33 -0
  5. data/lib/elastics.rb +108 -0
  6. data/lib/elastics/api_stubs.rb +1268 -0
  7. data/lib/elastics/api_templates/cluster_api.yml +94 -0
  8. data/lib/elastics/api_templates/core_api.yml +202 -0
  9. data/lib/elastics/api_templates/indices_api.yml +304 -0
  10. data/lib/elastics/class_proxy/base.rb +29 -0
  11. data/lib/elastics/class_proxy/templates.rb +97 -0
  12. data/lib/elastics/class_proxy/templates/doc.rb +91 -0
  13. data/lib/elastics/class_proxy/templates/search.rb +72 -0
  14. data/lib/elastics/configuration.rb +25 -0
  15. data/lib/elastics/deprecation.rb +153 -0
  16. data/lib/elastics/errors.rb +43 -0
  17. data/lib/elastics/http_clients/base.rb +15 -0
  18. data/lib/elastics/http_clients/loader.rb +51 -0
  19. data/lib/elastics/http_clients/patron.rb +29 -0
  20. data/lib/elastics/http_clients/rest_client.rb +36 -0
  21. data/lib/elastics/logger.rb +37 -0
  22. data/lib/elastics/prog_bar.rb +39 -0
  23. data/lib/elastics/rails.rb +1 -0
  24. data/lib/elastics/result.rb +24 -0
  25. data/lib/elastics/result/bulk.rb +20 -0
  26. data/lib/elastics/result/document.rb +67 -0
  27. data/lib/elastics/result/multi_get.rb +24 -0
  28. data/lib/elastics/result/search.rb +28 -0
  29. data/lib/elastics/struct/array.rb +25 -0
  30. data/lib/elastics/struct/hash.rb +105 -0
  31. data/lib/elastics/struct/paginable.rb +58 -0
  32. data/lib/elastics/struct/prunable.rb +60 -0
  33. data/lib/elastics/struct/symbolize.rb +27 -0
  34. data/lib/elastics/tasks.rb +62 -0
  35. data/lib/elastics/template.rb +124 -0
  36. data/lib/elastics/template/common.rb +42 -0
  37. data/lib/elastics/template/logger.rb +66 -0
  38. data/lib/elastics/template/partial.rb +28 -0
  39. data/lib/elastics/template/search.rb +30 -0
  40. data/lib/elastics/template/slim_search.rb +13 -0
  41. data/lib/elastics/template/tags.rb +56 -0
  42. data/lib/elastics/templates.rb +20 -0
  43. data/lib/elastics/utility_methods.rb +131 -0
  44. data/lib/elastics/utils.rb +103 -0
  45. data/lib/elastics/variables.rb +62 -0
  46. data/lib/tasks.rake +28 -0
  47. metadata +148 -0
@@ -0,0 +1,105 @@
1
+ module Elastics
2
+ module Struct
3
+ class Hash < ::Hash
4
+ include Symbolize
5
+
6
+ def initialize
7
+ super do |hash, key|
8
+ if key[-1] == '!'
9
+ klass = (key[0] == '_' ? Array : Hash)
10
+ hash[clean_key(key)] = klass.new
11
+ end
12
+ end
13
+ end
14
+
15
+ def merge(hash)
16
+ super symbolize(hash)
17
+ end
18
+
19
+ def merge!(hash)
20
+ super symbolize(hash)
21
+ end
22
+
23
+ def store(key, val)
24
+ if key[-1] == '='
25
+ super key[0..-2].to_sym, val.extend(AsIs)
26
+ else
27
+ super clean_key(key), symbolize(val)
28
+ end
29
+ end
30
+ alias_method :[]=, :store
31
+
32
+ def fetch(key, *rest, &block)
33
+ cleaned = clean_key(key)
34
+ super has_key?(cleaned) ? cleaned : key.to_sym, *rest, &block
35
+ end
36
+
37
+ def [](key)
38
+ cleaned = clean_key(key)
39
+ super has_key?(cleaned) ? cleaned : key.to_sym
40
+ end
41
+
42
+ def deep_merge(*hashes)
43
+ dupe = deep_dup(self)
44
+ hashes.each {|h2| dupe.replace(deep_merge_hash(dupe,h2))}
45
+ dupe
46
+ end
47
+
48
+ def deep_merge!(*hashes)
49
+ replace deep_merge(*hashes)
50
+ end
51
+
52
+ module Nil
53
+ def method_missing(*)
54
+ self
55
+ end
56
+ end
57
+
58
+ def try(key)
59
+ has_key?(key) ? self[key] : nil.extend(Nil)
60
+ end
61
+
62
+ def try_delete(key, *rest, &block)
63
+ val = delete clean_key(key), *rest, &block
64
+ val.nil? ? nil.extend(Nil) : val
65
+ end
66
+
67
+
68
+ private
69
+
70
+ def clean_key(key)
71
+ key[-1] == '!' ? key[0..-2].to_sym : key.to_sym
72
+ end
73
+
74
+ def deep_merge_hash(h1, h2)
75
+ h2 ||= {}
76
+ h1.merge(h2) do |key, oldval, newval|
77
+ case
78
+ when oldval.is_a?(Hash) && newval.is_a?(Hash)
79
+ deep_merge_hash(oldval, newval)
80
+ when oldval.is_a?(Array) && newval.is_a?(Array)
81
+ oldval | newval
82
+ else
83
+ newval
84
+ end
85
+ end
86
+ end
87
+
88
+ def deep_dup(obj)
89
+ case obj
90
+ when ::Hash, Elastics::Struct::Hash
91
+ h = obj.dup
92
+ h.each_pair do |k,v|
93
+ h[k] = deep_dup(v)
94
+ end
95
+ h
96
+ when ::Array, Elastics::Struct::Array
97
+ obj.map{|i| deep_dup(i)}
98
+ else
99
+ obj
100
+ end
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,58 @@
1
+ module Elastics
2
+ module Struct
3
+ module Paginable
4
+
5
+ attr_accessor :total_entries, :variables
6
+
7
+ def setup(total_entries, variables)
8
+ @total_entries = total_entries
9
+ @variables = variables
10
+ self
11
+ end
12
+
13
+ def per_page
14
+ (@variables[:per_page] || @variables[:limit_value] ||
15
+ @variables[:params] && @variables[:params][:size] || 10).to_i
16
+ end
17
+
18
+ def total_pages
19
+ ( @total_entries.to_f / per_page ).ceil
20
+ end
21
+
22
+ def current_page
23
+ (@variables[:page] || @variables[:current_page] || 1).to_i
24
+ end
25
+
26
+ def previous_page
27
+ current_page > 1 ? (current_page - 1) : nil
28
+ end
29
+
30
+ def next_page
31
+ current_page < total_pages ? (current_page + 1) : nil
32
+ end
33
+
34
+ def last_page?
35
+ total_pages == current_page
36
+ end
37
+
38
+ def first_page?
39
+ current_page == 1
40
+ end
41
+
42
+ def offset
43
+ per_page * (current_page - 1)
44
+ end
45
+
46
+ def out_of_bounds?
47
+ current_page > total_pages
48
+ end
49
+
50
+ alias_method :limit_value, :per_page
51
+ alias_method :total_count, :total_entries
52
+ alias_method :num_pages, :total_pages
53
+ alias_method :offset_value, :offset
54
+
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,60 @@
1
+ module Elastics
2
+ module Struct
3
+ module Prunable
4
+
5
+ extend self
6
+
7
+ VALUES = [ nil, '', {}, [], false ]
8
+
9
+ class Value
10
+ class << self
11
+ def to_s; '' end
12
+ alias_method :===, :==
13
+ end
14
+ end
15
+
16
+ def prune_blanks(obj)
17
+ prune(obj, *VALUES) || {}
18
+ end
19
+
20
+ # prunes the branch when the leaf is Prunable
21
+ # and compact.flatten the Array values
22
+ # values are the prunable values, like VALUES or Prunable::Value,
23
+ # or any arbitrary value
24
+ def prune(obj, *values)
25
+ case
26
+ when values.include?(obj)
27
+ obj
28
+ when obj.is_a?(::Array)
29
+ return obj if obj.empty?
30
+ ar = []
31
+ obj.each do |i|
32
+ pruned = prune(i, *values)
33
+ next if values.include?(pruned)
34
+ ar << pruned
35
+ end
36
+ a = ar.compact.flatten
37
+ a.empty? ? values.first : a
38
+ when obj.is_a?(::Hash)
39
+ return obj if obj.empty?
40
+ h = {}
41
+ obj.each do |k, v|
42
+ pruned = prune(v, *values)
43
+ next if values.include?(pruned)
44
+ # when a key is prunable merges the value if it is a hash (allows merging of partials)
45
+ if VALUES.include?(k)
46
+ h.merge!(pruned) if pruned.is_a?(::Hash)
47
+ else
48
+ h[k] = pruned
49
+ end
50
+ end
51
+ h.empty? ? values.first : h
52
+ else
53
+ obj
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ Prunable = Struct::Prunable
60
+ end
@@ -0,0 +1,27 @@
1
+ module Elastics
2
+ module Struct
3
+ module AsIs end
4
+ module Symbolize
5
+
6
+ def symbolize(obj)
7
+ case obj
8
+ when Elastics::Struct::Hash, Elastics::Struct::Array, Elastics::Struct::AsIs
9
+ obj
10
+ when ::Hash
11
+ h = Struct::Hash.new
12
+ obj.each do |k,v|
13
+ h[k.to_sym] = symbolize(v)
14
+ end
15
+ h
16
+ when ::Array
17
+ a = Struct::Array.new
18
+ obj.each{|i| a << i}
19
+ a
20
+ else
21
+ obj
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,62 @@
1
+ module Elastics
2
+ class Tasks
3
+
4
+ attr_reader :options
5
+
6
+ def initialize(overrides={})
7
+ options = Elastics::Utils.env2options *default_options.keys
8
+ options[:index] = options[:index].split(',') if options[:index]
9
+ @options = default_options.merge(options).merge(overrides)
10
+ end
11
+
12
+ def default_options
13
+ @default_options ||= { :force => false,
14
+ :index => Conf.variables[:index],
15
+ :config_file => Conf.config_file }
16
+ end
17
+
18
+ def create_indices
19
+ indices.each do |index|
20
+ delete_index(index) if options[:force]
21
+ raise ExistingIndexError, "#{index.inspect} already exists. Please use FORCE=1 if you want to delete it first." \
22
+ if exist?(index)
23
+ create(index)
24
+ end
25
+ end
26
+
27
+ def delete_indices
28
+ indices.each { |index| delete_index(index) }
29
+ end
30
+
31
+ def config_hash
32
+ @config_hash ||= ( hash = YAML.load(Utils.erb_process(config_path))
33
+ Utils.delete_allcaps_keys(hash) )
34
+ end
35
+
36
+ private
37
+
38
+ def indices
39
+ i = options[:index] || config_hash.keys
40
+ i.is_a?(Array) ? i : [i]
41
+ end
42
+
43
+ def exist?(index)
44
+ Elastics.exist?(:index => index)
45
+ end
46
+
47
+ def config_path
48
+ @config_path ||= options[:config_file] || Conf.config_file
49
+ end
50
+
51
+ def delete_index(index)
52
+ Elastics.delete_index(:index => index) if exist?(index)
53
+ end
54
+
55
+ def create(index)
56
+ config_hash[index] = {} unless config_hash.has_key?(index)
57
+ Elastics.POST "/#{index}", config_hash[index]
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,124 @@
1
+ module Elastics
2
+
3
+ # Generic Elastics::Template object.
4
+ # This class represents a generic Elastics::Template object.
5
+ # It is used as the base class by all the more specific Elastics::Template::* classes.
6
+ # You usually don't need to instantiate this class manually, since it is usually used internally.
7
+ # For more details about templates, see the documentation.
8
+ class Template
9
+
10
+ include Logger
11
+ include Common
12
+
13
+ def self.variables
14
+ Vars.new
15
+ end
16
+
17
+ attr_reader :method, :path
18
+
19
+ def initialize(method, path, data=nil, *vars)
20
+ @method = method.to_s.upcase
21
+ raise ArgumentError, "#@method method not supported" \
22
+ unless %w[HEAD GET PUT POST DELETE].include?(@method)
23
+ @path = path =~ /^\// ? path : "/#{path}"
24
+ @data = Utils.parse_source(data)
25
+ @instance_vars = Vars.new(*vars)
26
+ end
27
+
28
+ def render(*vars)
29
+ do_render(*vars) do |response, int|
30
+ Result.new(self, int[:vars], response).to_elastics_result
31
+ end
32
+ end
33
+
34
+ def to_a(*vars)
35
+ vars = Vars.new(*vars)
36
+ int = interpolate(vars)
37
+ a = [method, int[:path], Utils.keyfy(:to_s, int[:data]), Utils.keyfy(:to_s, @instance_vars)]
38
+ 2.times { a.pop if a.last.nil? || a.last.empty? }
39
+ a
40
+ end
41
+
42
+ def to_source
43
+ {@name.to_s => to_a}.to_yaml
44
+ end
45
+
46
+
47
+ private
48
+
49
+ def do_render(*vars)
50
+ vars = Vars.new(*vars)
51
+ int, path, encoded_data, response = try_clean_and_retry(vars)
52
+ return response.status == 200 if method == 'HEAD' # used in Elastics.exist?
53
+ if Conf.http_client.raise_proc.call(response)
54
+ int[:vars][:raise].is_a?(FalseClass) ? return : raise(HttpError.new(response, caller_line))
55
+ end
56
+ result = yield(response, int)
57
+ ensure
58
+ log_render(int, path, encoded_data, result)
59
+ result
60
+ end
61
+
62
+ # This allows to use Lucene style search language in the :cleanable_query declared variable and
63
+ # in case of a syntax error it will remove all the problematic characters and retry with a cleaned query_string
64
+ # http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html
65
+ def try_clean_and_retry(vars)
66
+ response_vars = request(vars)
67
+ if !Prunable::VALUES.include?(vars[:cleanable_query]) && Conf.http_client.raise_proc.call(response_vars[3])
68
+ e = HttpError.new(response_vars[3], caller_line)
69
+ e.to_hash['error'] =~ /^SearchPhaseExecutionException/
70
+ (vars[:cleanable_query].is_a?(String) ? vars[:cleanable_query] : vars[:cleanable_query][:query]).tr!('"&|!(){}[]~^:+-\\', '')
71
+ request vars
72
+ else
73
+ response_vars
74
+ end
75
+ end
76
+
77
+ def request(vars)
78
+ int = interpolate(vars, strict=true)
79
+ path = build_path(int, vars)
80
+ encoded_data = build_data(int, vars)
81
+ response = Conf.http_client.request(method, path, encoded_data)
82
+ return int, path, encoded_data, response
83
+ end
84
+
85
+ def build_path(int, vars)
86
+ params = int[:vars][:params]
87
+ path = vars[:path] || int[:path]
88
+ unless params.empty?
89
+ path << ((path =~ /\?/) ? '&' : '?')
90
+ path << params.map { |p| p.join('=') }.join('&')
91
+ end
92
+ path
93
+ end
94
+
95
+ def build_data(int, vars)
96
+ data = vars[:data] && Utils.parse_source(vars[:data]) || int[:data]
97
+ (data.nil? || data.is_a?(String)) ? data : MultiJson.encode(data)
98
+ end
99
+
100
+ def interpolate(*args)
101
+ tags = Tags.new
102
+ stringified = tags.stringify(:path => @path, :data => @data)
103
+ @partials, @tags = tags.partial_and_tag_names
104
+ @base_variables = Conf.variables.deep_merge(self.class.variables)
105
+ @temp_variables = Vars.new(@source_vars, @instance_vars, tags.variables)
106
+ instance_eval <<-ruby, __FILE__, __LINE__
107
+ def interpolate(vars={}, strict=false)
108
+ vars = Vars.new(vars) unless vars.is_a?(Elastics::Vars)
109
+ return {:path => path, :data => data, :vars => vars} if vars.empty? && !strict
110
+ context_variables = vars[:context] ? vars[:context].elastics.variables : (@host_elastics && @host_elastics.variables)
111
+ vars = @base_variables.deep_merge(context_variables, @temp_variables, vars).finalize
112
+ vars = interpolate_partials(vars)
113
+ obj = #{stringified}
114
+ obj = Prunable.prune(obj, Prunable::Value)
115
+ obj[:path].tr_s!('/', '/') # removes empty path segments
116
+ obj[:vars] = vars
117
+ obj
118
+ end
119
+ ruby
120
+ interpolate(*args)
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,42 @@
1
+ module Elastics
2
+ class Template
3
+ module Common
4
+
5
+ attr_reader :name, :partials, :tags, :data
6
+
7
+ def setup(host_elastics, name=nil, *vars)
8
+ @host_elastics = host_elastics
9
+ @name = name
10
+ @source_vars = Vars.new(*vars) if is_a?(Elastics::Template)
11
+ self
12
+ end
13
+
14
+ def interpolate_partials(vars)
15
+ @partials.each do |name|
16
+ partial_assigned_vars = vars[name]
17
+ next if Prunable::VALUES.include?(partial_assigned_vars)
18
+ vars[name] = case partial_assigned_vars
19
+ when Array
20
+ partial_assigned_vars.map {|v| @host_elastics.partials[name].interpolate(vars, v)}
21
+ # other partial name (usable as a case output)
22
+ when Symbol
23
+ @host_elastics.partials[partial_assigned_vars].interpolate(vars, vars[partial_assigned_vars])
24
+ # a partial object
25
+ when Template::Partial
26
+ partial_assigned_vars.interpolate(vars, vars)
27
+ # on-the-fly partial creation (an empty string would prune it before)
28
+ when String
29
+ Template::Partial.new(partial_assigned_vars).interpolate(vars, vars)
30
+ # switch to include the partial (a false value would prune it before)
31
+ when TrueClass
32
+ @host_elastics.partials[name].interpolate(vars, vars)
33
+ else
34
+ @host_elastics.partials[name].interpolate(vars, partial_assigned_vars)
35
+ end
36
+ end
37
+ vars
38
+ end
39
+
40
+ end
41
+ end
42
+ end