stretcher 1.4.0 → 1.5.0

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