stretcher 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -97,6 +97,7 @@ Specs may be run with `rake spec`
97
97
  * @psynix
98
98
  * @fmardini
99
99
  * @chatgris
100
+ * @alpinegizmo
100
101
 
101
102
  ## Contributing
102
103
 
@@ -4,9 +4,9 @@ module Stretcher
4
4
 
5
5
  # Many of the methods marked protected are called by one line shims in subclasses. This is mostly to facilitate
6
6
  # better looking rdocs
7
-
7
+
8
8
  private
9
-
9
+
10
10
  def do_search(generic_opts={}, explicit_body=nil)
11
11
  query_opts = {}
12
12
  body = nil
@@ -21,7 +21,7 @@ module Stretcher
21
21
  response = request(:get, "_search", query_opts) do |req|
22
22
  req.body = body
23
23
  end
24
- SearchResults.new(:raw => response)
24
+ SearchResults.new(:raw => response)
25
25
  end
26
26
 
27
27
  def do_refresh
@@ -33,5 +33,11 @@ module Stretcher
33
33
  raise "Cannot issue request, no server specified!" unless @server
34
34
  @server.request(method, prefixed_path, query_opts, *args, &block)
35
35
  end
36
+
37
+ def do_delete_query(query)
38
+ request :delete, '_query' do |req|
39
+ req.body = query
40
+ end
41
+ end
36
42
  end
37
43
  end
@@ -78,6 +78,10 @@ module Stretcher
78
78
  false
79
79
  end
80
80
 
81
+ def delete_query(query)
82
+ do_delete_query(query)
83
+ end
84
+
81
85
  # Issues a search with the given query opts and body, both should be hashes
82
86
  #
83
87
  # res = server.index('foo').search(size: 12, {query: {match_all: {}}})
@@ -117,7 +121,7 @@ module Stretcher
117
121
  req.body = text
118
122
  end
119
123
  end
120
-
124
+
121
125
  # Perform a refresh making all items in this index available instantly
122
126
  def refresh
123
127
  do_refresh
@@ -13,6 +13,7 @@ module Stretcher
13
13
 
14
14
  # Retrieves the document by ID
15
15
  # Normally this returns the contents of _source, however, the 'raw' flag is passed in, it will return the full response hash
16
+ # Returns nil if the document does not exist
16
17
  def get(id, raw=false)
17
18
  res = request(:get, id)
18
19
  raw ? res : res["_source"]
@@ -23,6 +24,11 @@ module Stretcher
23
24
  request(:put, id, source)
24
25
  end
25
26
 
27
+ # Index an item with automatic ID generation
28
+ def post(source)
29
+ request(:post, nil, source)
30
+ end
31
+
26
32
  # Uses the update api to modify a document with a script
27
33
  # To update a doc with ID 987 for example:
28
34
  # type.update(987, script: "ctx._source.message = 'Updated!'")
@@ -63,11 +69,14 @@ module Stretcher
63
69
  def exists?(id=nil)
64
70
  request :head, id
65
71
  true
66
- rescue Stretcher::RequestError => e
67
- raise e if e.http_response.status != 404
72
+ rescue Stretcher::RequestError::NotFound => e
68
73
  false
69
74
  end
70
75
 
76
+ def delete_query(query)
77
+ do_delete_query(query)
78
+ end
79
+
71
80
  # Issues an Index#search scoped to this type
72
81
  # See Index#search for more details
73
82
  def search(generic_opts={}, explicit_body=nil)
@@ -2,9 +2,12 @@ module Stretcher
2
2
  # Raised when the underlying http status of an operation != 200
3
3
  class RequestError < StandardError
4
4
  attr_reader :http_response
5
-
5
+
6
6
  def initialize(http_response)
7
7
  @http_response = http_response
8
8
  end
9
+
10
+ class NotFound < RequestError
11
+ end
9
12
  end
10
13
  end
@@ -18,9 +18,11 @@ module Stretcher
18
18
  super
19
19
  self.total = raw.hits.total
20
20
  self.facets = raw.facets
21
- self.results = raw.hits.hits.collect {|r|
22
- (r.has_key?('_source') ? r['_source'] : r['fields']).merge({"_id" => r['_id']})
23
- }
21
+ self.results = raw.hits.hits.collect do |r|
22
+ k = ['_source', 'fields'].detect { |k| r.key?(k) }
23
+ doc = k.nil? ? Hashie::Mash.new : r[k]
24
+ doc.merge({"_id" => r['_id']})
25
+ end
24
26
  end
25
27
  end
26
28
  end
@@ -119,7 +119,7 @@ module Stretcher
119
119
  req.body = text
120
120
  end
121
121
  end
122
-
122
+
123
123
  # Perform a refresh, making all indexed documents available
124
124
  def refresh
125
125
  do_refresh
@@ -146,6 +146,10 @@ module Stretcher
146
146
 
147
147
  if res.status >= 200 && res.status <= 299
148
148
  res.body
149
+ elsif res.status == 404
150
+ err_str = "Error 404 processing request: (#{res.status})! #{res.env[:method]} URL: #{res.env[:url]}"
151
+ err_str << "\n Resp Body: #{res.body}"
152
+ raise RequestError::NotFound.new(res), err_str
149
153
  else
150
154
  err_str = "Error processing request (#{res.status})! #{res.env[:method]} URL: #{res.env[:url]}"
151
155
  err_str << "\n Resp Body: #{res.body}"
@@ -3,7 +3,7 @@ module Stretcher
3
3
  def self.qurl(url, query_opts=nil)
4
4
  query_opts && !query_opts.empty? ? "#{url}?#{querify(query_opts)}" : url
5
5
  end
6
-
6
+
7
7
  def self.querify(hash)
8
8
  hash.map {|k,v| "#{k}=#{v}"}.join('&')
9
9
  end
@@ -1,3 +1,3 @@
1
1
  module Stretcher
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -4,7 +4,16 @@ describe Stretcher::Index do
4
4
  let(:server) {
5
5
  Stretcher::Server.new(ES_URL, :logger => DEBUG_LOGGER)
6
6
  }
7
- let(:index) { server.index('foo') }
7
+ let(:index) {
8
+ i = server.index('foo')
9
+ i.delete
10
+ server.refresh
11
+ i.create
12
+ # Why do both? Doesn't hurt, and it fixes some races
13
+ server.refresh
14
+ i.refresh
15
+ i
16
+ }
8
17
  let(:corpus) {
9
18
  [
10
19
  {:text => "Foo", "_type" => 'tweet', "_id" => 'fooid'},
@@ -21,6 +30,7 @@ describe Stretcher::Index do
21
30
  def seed_corpus
22
31
  create_tweet_mapping
23
32
  index.bulk_index(corpus)
33
+ index.refresh
24
34
  end
25
35
 
26
36
  it "should work on an existential level" do
@@ -63,6 +73,14 @@ describe Stretcher::Index do
63
73
  }
64
74
  end
65
75
 
76
+ it "should delete by query" do
77
+ seed_corpus
78
+ index.search(:query => {:match_all => {}}).total == 3
79
+ index.delete_query(:match_all => {})
80
+ index.refresh
81
+ index.search(:query => {:match_all => {}}).total == 0
82
+ end
83
+
66
84
  it "should search without error" do
67
85
  seed_corpus
68
86
  match_text = corpus.first[:text]
@@ -80,7 +98,7 @@ describe Stretcher::Index do
80
98
  end
81
99
 
82
100
  it "execute the analysis API and return an expected result" do
83
- analyzed = index.analyze("Candles", :analyzer => :snowball)
101
+ analyzed = server.index(:foo).analyze("Candles", :analyzer => :snowball)
84
102
  analyzed.tokens.first.token.should == 'candl'
85
103
  end
86
104
 
@@ -1,29 +1,38 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Stretcher::Index do
3
+ describe Stretcher::IndexType do
4
4
  let(:server) { Stretcher::Server.new(ES_URL) }
5
- let(:index) { server.index('foo') }
6
- let(:type) { index.type('bar') }
5
+ let(:index) {
6
+ i = server.index(:foo)
7
+ i
8
+ }
9
+ let(:type) {
10
+ t = index.type(:bar)
11
+ t.delete_query(:match_all => {})
12
+ index.refresh
13
+ mapping = {"bar" => {"properties" => {"message" => {"type" => "string"}}}}
14
+ t.put_mapping mapping
15
+ t
16
+ }
7
17
 
8
18
  it "should be existentially aware" do
9
- type.delete rescue nil
10
- type.exists?.should be_false
11
- mapping = {"bar" => {"properties" => {"message" => {"type" => "string"}}}}
12
- type.put_mapping mapping
13
- type.exists?.should be_true
14
- type.get_mapping.should == mapping
19
+ t = index.type(:existential)
20
+ t.exists?.should be_false
21
+ mapping = {"existential" => {"properties" => {"message" => {"type" => "string"}}}}
22
+ t.put_mapping mapping
23
+ t.exists?.should be_true
24
+ t.get_mapping.should == mapping
15
25
  end
16
26
 
17
27
  describe "searching" do
18
28
  before do
19
29
  @doc = {:message => "hello"}
30
+ type.put(123123, @doc)
31
+ index.refresh
20
32
  end
21
33
 
22
34
  it "should search and find the right doc" do
23
- match_text = 'hello'
24
- type.put(123123, @doc)
25
- index.refresh
26
- res = type.search({}, {:query => {:match => {:message => match_text}}})
35
+ res = type.search({}, {:query => {:match => {:message => @doc[:message]}}})
27
36
  res.results.first.message.should == @doc[:message]
28
37
  end
29
38
 
@@ -31,21 +40,37 @@ describe Stretcher::Index do
31
40
  res = type.search({}, {query: {match_all: {}}, fields: ['message']})
32
41
  res.results.first.message.should == @doc[:message]
33
42
  end
43
+
44
+ it "should build results when no document fields are selected" do
45
+ res = type.search({}, {query: {match_all: {}}, fields: ['_id']})
46
+ res.results.first.should have_key '_id'
47
+ end
34
48
  end
35
49
 
36
- describe "put/get" do
50
+ describe "put/get/delete" do
37
51
  before do
38
52
  @doc = {:message => "hello!"}
53
+ @put_res = type.put(987, @doc)
39
54
  end
40
55
 
41
56
  it "should put correctly" do
42
- type.put(987, @doc).should_not be_nil
57
+ @put_res.should_not be_nil
58
+ end
59
+
60
+ it "should post correctly" do
61
+ type.post(@doc).should_not be_nil
43
62
  end
44
63
 
45
64
  it "should get individual documents correctly" do
46
65
  type.get(987).message.should == @doc[:message]
47
66
  end
48
67
 
68
+ it "should return nil when retrieving non-extant docs" do
69
+ lambda {
70
+ type.get(898323329)
71
+ }.should raise_exception(Stretcher::RequestError::NotFound)
72
+ end
73
+
49
74
  it "should get individual raw documents correctly" do
50
75
  res = type.get(987, true)
51
76
  res["_id"].should == "987"
@@ -57,6 +82,12 @@ describe Stretcher::Index do
57
82
  type.get(987).message.should == 'Updated!'
58
83
  end
59
84
 
85
+ it "should delete by query correctly" do
86
+ type.delete_query("match_all" => {})
87
+ index.refresh
88
+ type.exists?(987).should be_false
89
+ end
90
+
60
91
  it "should delete individual docs correctly" do
61
92
  type.exists?(987).should be_true
62
93
  type.delete(987)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stretcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-05 00:00:00.000000000 Z
12
+ date: 2013-03-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday