elastics-client 1.0.4

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 (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