mwmitchell-rsolr-ext 0.7.35 → 0.8.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.rdoc +6 -6
- data/lib/rsolr-ext/{findable.rb → connection.rb} +7 -12
- data/lib/rsolr-ext/doc.rb +35 -88
- data/lib/rsolr-ext/model.rb +98 -0
- data/lib/rsolr-ext/request.rb +84 -47
- data/lib/rsolr-ext/response/docs.rb +1 -43
- data/lib/rsolr-ext/response/facets.rb +4 -14
- data/lib/rsolr-ext/response.rb +10 -37
- data/lib/rsolr-ext.rb +6 -18
- data/rsolr-ext.gemspec +6 -7
- data/test/{findable_test.rb → connection_test.rb} +1 -1
- data/test/request_test.rb +12 -5
- data/test/response_test.rb +4 -4
- metadata +7 -7
- data/lib/rsolr-ext/mapable.rb +0 -44
- data/lib/rsolr-ext/request/queryable.rb +0 -47
data/README.rdoc
CHANGED
@@ -14,12 +14,12 @@ A set of helper methods/modules to assist in building Solr queries and handling
|
|
14
14
|
|
15
15
|
rsolr = RSolr::Ext.connect
|
16
16
|
|
17
|
-
response = rsolr.
|
17
|
+
response = rsolr.find(solr_params)
|
18
18
|
|
19
19
|
==Response Example
|
20
20
|
rsolr = RSolr::Ext.connect
|
21
21
|
|
22
|
-
response = rsolr.
|
22
|
+
response = rsolr.find :q=>'*:*'
|
23
23
|
|
24
24
|
response.ok?
|
25
25
|
response.params
|
@@ -34,15 +34,15 @@ You can access values in the response hash using symbols or strings.
|
|
34
34
|
If you wanna paginate, just throw the collection into the WillPaginate view helper.
|
35
35
|
<%= will_paginate response.docs %>
|
36
36
|
|
37
|
-
===The
|
38
|
-
You can create your own "models" using RSolr::Ext::
|
37
|
+
===The "Model" Module
|
38
|
+
You can create your own <read-only> "models" using RSolr::Ext::Model
|
39
39
|
|
40
40
|
class Book
|
41
|
-
include RSolr::Ext::
|
41
|
+
include RSolr::Ext::Model
|
42
42
|
def self.find_by_author(author)
|
43
43
|
find(:fq=>'object_type:"book"', :rows=>10, :phrase_filters=>{:author=>author})
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
all_books = Book.find('*:*')
|
48
|
-
hawk_books = Book.find_by_author('hawk')
|
48
|
+
hawk_books = Book.find_by_author('hawk')
|
@@ -1,6 +1,5 @@
|
|
1
|
-
# Findable can be mixed into whatever RSolr.connect returns.
|
2
1
|
# RSolr::Ext.connect() does this for you.
|
3
|
-
#
|
2
|
+
# Ext::Connection makes querying solr easier by providing a simple #find method.
|
4
3
|
#
|
5
4
|
# The #find method behaves differently depending on what you send in.
|
6
5
|
#
|
@@ -24,32 +23,26 @@
|
|
24
23
|
# The following opts are allowed:
|
25
24
|
# :include_response - false is default - whether or not to return the whole solr response or just the doc(s)
|
26
25
|
# :handler - nil is default - the request path (/select or /search etc.)
|
27
|
-
module RSolr::Ext::
|
26
|
+
module RSolr::Ext::Connection
|
28
27
|
|
29
28
|
# Examples:
|
30
29
|
# find 'jefferson' # q=jefferson - all docs
|
31
30
|
# find :first, 'jefferson' # q=jefferson&rows=1 - first doc only
|
32
31
|
# find 'jefferson', :phrase_filters=>{:type=>'book'} # q=jefferson&fq=type:"book" - all docs
|
33
32
|
# find {:q=>'something'}, :include_response=>true # q=something -- the entire response
|
34
|
-
def find
|
33
|
+
def find *args, &blk
|
35
34
|
mode, solr_params, opts = extract_find_opts!(*args)
|
36
35
|
|
37
36
|
opts[:include_response] ||= true
|
38
37
|
|
39
38
|
solr_params[:rows] = 1 if mode == :first
|
40
|
-
valid_solr_params = RSolr::Ext.
|
39
|
+
valid_solr_params = RSolr::Ext::Request.map(solr_params)
|
41
40
|
|
42
41
|
response = opts[:handler] ? send_request(opts[:handler], valid_solr_params) : select(valid_solr_params)
|
43
42
|
return response if response.is_a?(String)
|
44
43
|
|
45
|
-
response = RSolr::Ext::
|
44
|
+
response = RSolr::Ext::Response::Base.new(response)
|
46
45
|
|
47
|
-
if block_given? and response['response']['docs']
|
48
|
-
# yield each doc if a block is given
|
49
|
-
response['response']['docs'].each_with_index do |doc,i|
|
50
|
-
response['response']['docs'][i] = yield(doc)
|
51
|
-
end
|
52
|
-
end
|
53
46
|
if opts[:include_response] == true
|
54
47
|
response
|
55
48
|
else
|
@@ -85,6 +78,8 @@ module RSolr::Ext::Findable
|
|
85
78
|
end
|
86
79
|
# extract solr params
|
87
80
|
solr_params = args.shift
|
81
|
+
# if solr_params is NOT a hash like object
|
82
|
+
# force it into a string for the :q param
|
88
83
|
unless solr_params.respond_to?(:each_pair)
|
89
84
|
solr_params = {:q=>solr_params.to_s}
|
90
85
|
end
|
data/lib/rsolr-ext/doc.rb
CHANGED
@@ -1,97 +1,44 @@
|
|
1
|
-
# include this module into a plain ruby class:
|
2
|
-
# class Book
|
3
|
-
# include RSolr::Ext::Doc
|
4
|
-
# connection = RSolr::Ext.connect
|
5
|
-
# default_params = {:phrase_filters=>'type:book'}
|
6
|
-
# end
|
7
|
-
#
|
8
|
-
# Then:
|
9
|
-
# number_10 = Book.find_by_id(10)
|
10
|
-
#
|
11
1
|
module RSolr::Ext::Doc
|
12
2
|
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
# creates the @hooks container ("hooks" are blocks or procs).
|
17
|
-
# returns an array
|
18
|
-
def hooks
|
19
|
-
@hooks ||= []
|
20
|
-
end
|
21
|
-
|
22
|
-
# method that only accepts a block
|
23
|
-
# The block is executed when an object is created via #new -> SolrDoc.new
|
24
|
-
# The blocks scope is the instance of the object.
|
25
|
-
def after_initialize(&blk)
|
26
|
-
hooks << blk
|
27
|
-
end
|
28
|
-
|
29
|
-
# Removes the current set of after_initialize blocks.
|
30
|
-
# You would use this if you wanted to open a class back up,
|
31
|
-
# but clear out the previously defined blocks.
|
32
|
-
def clear_after_initialize_blocks!
|
33
|
-
@hooks = []
|
34
|
-
end
|
35
|
-
|
3
|
+
# for easy access to the solr id (route helpers etc..)
|
4
|
+
def id
|
5
|
+
self['id']
|
36
6
|
end
|
37
7
|
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
8
|
+
# Helper method to check if value/multi-values exist for a given key.
|
9
|
+
# The value can be a string, or a RegExp
|
10
|
+
# Multiple "values" can be given; only one needs to match.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# doc.has?(:location_facet)
|
14
|
+
# doc.has?(:location_facet, 'Clemons')
|
15
|
+
# doc.has?(:id, 'h009', /^u/i)
|
16
|
+
def has?(k, *values)
|
17
|
+
return if self[k].nil?
|
18
|
+
return true if self.key?(k) and values.empty?
|
19
|
+
target = self[k]
|
20
|
+
if target.is_a?(Array)
|
21
|
+
values.each do |val|
|
22
|
+
return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
|
23
|
+
end
|
24
|
+
else
|
25
|
+
return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
|
48
26
|
end
|
49
|
-
|
50
|
-
def find(*args)
|
51
|
-
mode, solr_params, opts = connection.send(:extract_find_opts!, *args)
|
52
|
-
connection.find(*[mode, solr_params, opts]) { |doc| self.new(doc) }
|
53
|
-
end
|
54
|
-
|
55
|
-
def find_by_id(id, solr_params={}, opts={})
|
56
|
-
connection.find_by_id(id, solr_params, opts) { |doc| self.new(doc) }
|
57
|
-
end
|
58
|
-
|
59
27
|
end
|
60
|
-
|
61
|
-
#
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
# Constructor **for the class that is getting this module included**
|
75
|
-
# source_doc should be a hash or something similar
|
76
|
-
# calls each of after_initialize blocks
|
77
|
-
def initialize(source_doc={})
|
78
|
-
@_source_hash = source_doc
|
79
|
-
@_source_mash = source_doc.to_mash
|
80
|
-
self.class.hooks.each do |h|
|
81
|
-
instance_eval &h
|
28
|
+
|
29
|
+
# helper
|
30
|
+
# key is the name of the field
|
31
|
+
# opts is a hash with the following valid keys:
|
32
|
+
# - :sep - a string used for joining multivalued field values
|
33
|
+
# - :default - a value to return when the key doesn't exist
|
34
|
+
# if :sep is nil and the field is a multivalued field, the array is returned
|
35
|
+
def get key, opts={:sep=>', ', :default=>nil}
|
36
|
+
if self.key? key
|
37
|
+
val = self[key]
|
38
|
+
(val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
|
39
|
+
else
|
40
|
+
opts[:default]
|
82
41
|
end
|
83
42
|
end
|
84
|
-
|
85
|
-
# for easy access to the solr id (route helpers etc..)
|
86
|
-
def id
|
87
|
-
@_source_mash['id']
|
88
|
-
end
|
89
|
-
|
90
|
-
# the wrapper method to the @_source_hash object.
|
91
|
-
# If a method is missing, it gets sent to @_source_hash
|
92
|
-
# with all of the original params and block
|
93
|
-
def method_missing(m, *args, &b)
|
94
|
-
@_source_mash.send(m, *args, &b)
|
95
|
-
end
|
96
|
-
|
43
|
+
|
97
44
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# include this module into a plain ruby class:
|
2
|
+
# class Book
|
3
|
+
# include RSolr::Ext::Model
|
4
|
+
# connection = RSolr::Ext.connect
|
5
|
+
# default_params = {:phrase_filters=>'type:book'}
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# Then:
|
9
|
+
# number_10 = Book.find_by_id(10)
|
10
|
+
#
|
11
|
+
module RSolr::Ext::Model
|
12
|
+
|
13
|
+
# Class level methods for altering object instances
|
14
|
+
module Callbacks
|
15
|
+
|
16
|
+
# method that only accepts a block
|
17
|
+
# The block is executed when an object is created via #new -> SolrDoc.new
|
18
|
+
# The blocks scope is the instance of the object.
|
19
|
+
def after_initialize(&blk)
|
20
|
+
hooks << blk
|
21
|
+
end
|
22
|
+
|
23
|
+
# Removes the current set of after_initialize blocks.
|
24
|
+
# You would use this if you wanted to open a class back up,
|
25
|
+
# but clear out the previously defined blocks.
|
26
|
+
def clear_after_initialize_blocks!
|
27
|
+
@hooks = []
|
28
|
+
end
|
29
|
+
|
30
|
+
# creates the @hooks container ("hooks" are blocks or procs).
|
31
|
+
# returns an array
|
32
|
+
def hooks
|
33
|
+
@hooks ||= []
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Findable is a module that gets mixed into the SolrDocument class object.
|
40
|
+
# These methods will be available through the class like: SolrDocument.find and SolrDocument.find_by_id
|
41
|
+
#
|
42
|
+
module Findable
|
43
|
+
|
44
|
+
attr_accessor :connection, :default_params
|
45
|
+
|
46
|
+
def connection
|
47
|
+
@connection ||= RSolr::Ext.connect
|
48
|
+
end
|
49
|
+
|
50
|
+
# this method decorates the connection find method
|
51
|
+
# and then creates new instance of the class that uses this module.
|
52
|
+
def find(*args)
|
53
|
+
decorate_response_docs connection.find(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
# this method decorates the connection find_by_id method
|
57
|
+
# and then creates new instance of the class that uses this module.
|
58
|
+
def find_by_id(id, solr_params={}, opts={})
|
59
|
+
decorate_response_docs connection.find_by_id(id, solr_params, opts)
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def decorate_response_docs response
|
65
|
+
response['response']['docs'].map!{|d| self.new d }
|
66
|
+
response
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
# Called by Ruby Module API
|
72
|
+
# extends this *class* object
|
73
|
+
def self.included(base)
|
74
|
+
base.extend Callbacks
|
75
|
+
base.extend Findable
|
76
|
+
end
|
77
|
+
|
78
|
+
# The original object passed in to the #new method
|
79
|
+
attr :_source
|
80
|
+
|
81
|
+
# Constructor **for the class that is getting this module included**
|
82
|
+
# source_doc should be a hash or something similar
|
83
|
+
# calls each of after_initialize blocks
|
84
|
+
def initialize(source_doc={})
|
85
|
+
@_source = source_doc
|
86
|
+
self.class.hooks.each do |h|
|
87
|
+
instance_eval &h
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# the wrapper method to the @_source object.
|
92
|
+
# If a method is missing, it gets sent to @_source
|
93
|
+
# with all of the original params and block
|
94
|
+
def method_missing(m, *args, &b)
|
95
|
+
@_source.send(m, *args, &b)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
data/lib/rsolr-ext/request.rb
CHANGED
@@ -1,64 +1,101 @@
|
|
1
1
|
module RSolr::Ext::Request
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class Standard
|
6
|
-
|
7
|
-
include RSolr::Ext::Mapable
|
8
|
-
include RSolr::Ext::Request::Queryable
|
9
|
-
|
10
|
-
MAPPED_PARAMS = [
|
11
|
-
:per_page,
|
12
|
-
:page,
|
13
|
-
:queries, # fielded queries
|
14
|
-
:phrases, # quoted q param
|
15
|
-
:filters, # fq params
|
16
|
-
:phrase_filters, # quoted fq params,
|
17
|
-
:facets
|
18
|
-
]
|
3
|
+
module Params
|
19
4
|
|
20
|
-
def
|
21
|
-
output
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
page =
|
27
|
-
|
28
|
-
|
5
|
+
def map input
|
6
|
+
output = {}
|
7
|
+
if input[:per_page]
|
8
|
+
output[:rows] = input.delete :per_page
|
9
|
+
end
|
10
|
+
|
11
|
+
if page = input.delete(:page)
|
12
|
+
raise ':per_page must be set when using :page' unless output[:rows]
|
13
|
+
page = page.to_s.to_i-1
|
14
|
+
page = page < 1 ? 0 : page
|
15
|
+
output[:start] = page * output[:rows]
|
16
|
+
end
|
17
|
+
|
18
|
+
if queries = input.delete(:queries)
|
19
|
+
output[:q] = append_to_param output[:q], build_query(queries, false)
|
20
|
+
end
|
21
|
+
if phrases = input.delete(:phrases)
|
22
|
+
output[:q] = append_to_param output[:q], build_query(phrases, true)
|
23
|
+
end
|
24
|
+
if filters = input.delete(:filters)
|
25
|
+
output[:fq] = append_to_param output[:fq], build_query(filters), false
|
26
|
+
end
|
27
|
+
if pfilters = input.delete(:phrase_filters)
|
28
|
+
output[:fq] = append_to_param output[:fq], build_query(pfilters, true), false
|
29
|
+
end
|
30
|
+
if facets = input.delete(:facets)
|
31
|
+
output[:facet] = true
|
32
|
+
output['facet.field'] = append_to_param output['facet.field'], build_query(facets.values), false
|
33
|
+
end
|
34
|
+
output.merge input
|
29
35
|
end
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
end
|
38
|
+
|
39
|
+
module QueryHelpers
|
34
40
|
|
35
|
-
|
36
|
-
|
41
|
+
# Wraps a string around double quotes
|
42
|
+
def quote(value)
|
43
|
+
%("#{value}")
|
37
44
|
end
|
38
45
|
|
39
|
-
|
40
|
-
|
46
|
+
# builds a solr range query from a Range object
|
47
|
+
def build_range(r)
|
48
|
+
"[#{r.min} TO #{r.max}]"
|
41
49
|
end
|
42
50
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
# builds a solr query fragment
|
52
|
+
# if "quote_string" is true, the values will be quoted.
|
53
|
+
# if "value" is a string/symbol, the #to_s method is called
|
54
|
+
# if the "value" is an array, each item in the array is
|
55
|
+
# send to build_query (recursive)
|
56
|
+
# if the "value" is a Hash, a fielded query is built
|
57
|
+
# where the keys are used as the field names and
|
58
|
+
# the values are either processed as a Range or
|
59
|
+
# passed back into build_query (recursive)
|
60
|
+
def build_query(value, quote_string=false)
|
61
|
+
case value
|
62
|
+
when String,Symbol
|
63
|
+
quote_string ? quote(value.to_s) : value.to_s
|
64
|
+
when Array
|
65
|
+
value.collect do |v|
|
66
|
+
build_query(v, quote_string)
|
67
|
+
end.flatten
|
68
|
+
when Hash
|
69
|
+
return value.collect do |(k,v)|
|
70
|
+
if v.is_a?(Range)
|
71
|
+
"#{k}:#{build_range(v)}"
|
72
|
+
# If the value is an array, we want the same param, multiple times (not a query join)
|
73
|
+
elsif v.is_a?(Array)
|
74
|
+
v.collect do |vv|
|
75
|
+
"#{k}:#{build_query(vv, quote_string)}"
|
76
|
+
end
|
77
|
+
else
|
78
|
+
"#{k}:#{build_query(v, quote_string)}"
|
79
|
+
end
|
80
|
+
end.flatten
|
55
81
|
end
|
56
82
|
end
|
83
|
+
|
84
|
+
# creates an array where the "existing_value" param is first
|
85
|
+
# and the "new_value" is the last.
|
86
|
+
# All empty/nil items are removed.
|
87
|
+
# the return result is either the result of the
|
88
|
+
# array being joined on a space, or the array itself.
|
89
|
+
# "auto_join" should be true or false.
|
90
|
+
def append_to_param(existing_value, new_value, auto_join=true)
|
91
|
+
values = [existing_value, new_value]
|
92
|
+
values.delete_if{|v|v.nil?}
|
93
|
+
auto_join ? values.join(' ') : values.flatten
|
94
|
+
end
|
57
95
|
|
58
96
|
end
|
59
97
|
|
60
|
-
|
61
|
-
|
62
|
-
end
|
98
|
+
extend QueryHelpers
|
99
|
+
extend Params
|
63
100
|
|
64
101
|
end
|
@@ -1,45 +1,5 @@
|
|
1
1
|
module RSolr::Ext::Response::Docs
|
2
2
|
|
3
|
-
module Accessible
|
4
|
-
|
5
|
-
# Helper method to check if value/multi-values exist for a given key.
|
6
|
-
# The value can be a string, or a RegExp
|
7
|
-
# Multiple "values" can be given; only one needs to match.
|
8
|
-
#
|
9
|
-
# Example:
|
10
|
-
# doc.has?(:location_facet)
|
11
|
-
# doc.has?(:location_facet, 'Clemons')
|
12
|
-
# doc.has?(:id, 'h009', /^u/i)
|
13
|
-
def has?(k, *values)
|
14
|
-
return if self[k].nil?
|
15
|
-
return true if self.key?(k) and values.empty?
|
16
|
-
target = self[k]
|
17
|
-
if target.is_a?(Array)
|
18
|
-
values.each do |val|
|
19
|
-
return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
|
20
|
-
end
|
21
|
-
else
|
22
|
-
return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# helper
|
27
|
-
# key is the name of the field
|
28
|
-
# opts is a hash with the following valid keys:
|
29
|
-
# - :sep - a string used for joining multivalued field values
|
30
|
-
# - :default - a value to return when the key doesn't exist
|
31
|
-
# if :sep is nil and the field is a multivalued field, the array is returned
|
32
|
-
def get(key, opts={:sep=>', ', :default=>nil})
|
33
|
-
if self.key? key
|
34
|
-
val = self[key]
|
35
|
-
(val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
|
36
|
-
else
|
37
|
-
opts[:default]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
3
|
module Pageable
|
44
4
|
|
45
5
|
attr_accessor :start, :per_page, :total
|
@@ -82,10 +42,8 @@ module RSolr::Ext::Response::Docs
|
|
82
42
|
|
83
43
|
def self.extended(base)
|
84
44
|
d = base['response']['docs']
|
45
|
+
d.each{|doc| doc.extend RSolr::Ext::Doc }
|
85
46
|
d.extend Pageable
|
86
|
-
d.each do |item|
|
87
|
-
item.extend Accessible
|
88
|
-
end
|
89
47
|
d.per_page = base['responseHeader']['params']['rows'].to_s.to_i
|
90
48
|
d.start = base['response']['start'].to_s.to_i
|
91
49
|
d.total = base['response']['numFound'].to_s.to_i
|
@@ -1,23 +1,13 @@
|
|
1
1
|
module RSolr::Ext::Response::Facets
|
2
2
|
|
3
3
|
# represents a facet value; which is a field value and its hit count
|
4
|
-
|
5
|
-
attr_reader :value,:hits
|
6
|
-
def initialize(value,hits)
|
7
|
-
@value,@hits=value,hits
|
8
|
-
end
|
9
|
-
end
|
4
|
+
FacetItem = Struct.new :value,:hits
|
10
5
|
|
11
6
|
# represents a facet; which is a field and its values
|
12
|
-
|
13
|
-
|
14
|
-
attr_accessor :items
|
15
|
-
def initialize(name)
|
16
|
-
@name=name
|
17
|
-
@items=[]
|
18
|
-
end
|
7
|
+
FacetField = Struct.new :name, :items do
|
8
|
+
def items; @items ||= [] end
|
19
9
|
end
|
20
|
-
|
10
|
+
|
21
11
|
# @response.facets.each do |facet|
|
22
12
|
# facet.field
|
23
13
|
# end
|
data/lib/rsolr-ext/response.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
module RSolr::Ext::Response
|
2
2
|
|
3
|
-
autoload :Facets, 'rsolr-ext/response/facets'
|
4
3
|
autoload :Docs, 'rsolr-ext/response/docs'
|
4
|
+
autoload :Facets, 'rsolr-ext/response/facets'
|
5
5
|
autoload :Spelling, 'rsolr-ext/response/spelling'
|
6
6
|
|
7
7
|
class Base < Mash
|
8
8
|
|
9
|
+
def initialize *args
|
10
|
+
super *args
|
11
|
+
extend Response if self['response']
|
12
|
+
extend Docs if self['response'] and self['response']['docs']
|
13
|
+
extend Facets if self['facet_counts']
|
14
|
+
extend Spelling if self['spellcheck']
|
15
|
+
end
|
16
|
+
|
9
17
|
def header
|
10
18
|
self['responseHeader']
|
11
19
|
end
|
@@ -20,15 +28,7 @@ module RSolr::Ext::Response
|
|
20
28
|
|
21
29
|
end
|
22
30
|
|
23
|
-
|
24
|
-
class Standard < Base
|
25
|
-
|
26
|
-
def initialize(*args)
|
27
|
-
super(*args)
|
28
|
-
extend Docs
|
29
|
-
extend Facets
|
30
|
-
extend Spelling
|
31
|
-
end
|
31
|
+
module Response
|
32
32
|
|
33
33
|
def response
|
34
34
|
self[:response]
|
@@ -41,31 +41,4 @@ module RSolr::Ext::Response
|
|
41
41
|
|
42
42
|
end
|
43
43
|
|
44
|
-
class Dismax < Standard
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
#
|
49
|
-
class Luke < Base
|
50
|
-
|
51
|
-
# Returns an array of fields from the index
|
52
|
-
# An optional rule can be used for "grepping" field names:
|
53
|
-
# field_list(/_facet$/)
|
54
|
-
def field_list(rule=nil)
|
55
|
-
fields.select do |k,v|
|
56
|
-
rule ? k =~ rule : true
|
57
|
-
end.collect{|k,v|k}
|
58
|
-
end
|
59
|
-
|
60
|
-
def fields
|
61
|
-
self['fields']
|
62
|
-
end
|
63
|
-
|
64
|
-
end# end Luke
|
65
|
-
|
66
|
-
# Update
|
67
|
-
class Update < Base
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
44
|
end
|
data/lib/rsolr-ext.rb
CHANGED
@@ -4,9 +4,7 @@ lambda { |base|
|
|
4
4
|
$: << base unless $:.include?(base) || $:.include?(File.expand_path(base))
|
5
5
|
}.call(File.dirname(__FILE__))
|
6
6
|
|
7
|
-
unless defined?(Mash)
|
8
|
-
require 'mash'
|
9
|
-
end
|
7
|
+
require 'mash' unless defined?(Mash)
|
10
8
|
|
11
9
|
unless Hash.respond_to?(:to_mash)
|
12
10
|
class Hash
|
@@ -23,29 +21,19 @@ module RSolr
|
|
23
21
|
|
24
22
|
module Ext
|
25
23
|
|
26
|
-
VERSION = '0.
|
24
|
+
VERSION = '0.8.0'
|
27
25
|
|
26
|
+
autoload :Connection, 'rsolr-ext/connection.rb'
|
27
|
+
autoload :Doc, 'rsolr-ext/doc.rb'
|
28
28
|
autoload :Request, 'rsolr-ext/request.rb'
|
29
29
|
autoload :Response, 'rsolr-ext/response.rb'
|
30
|
-
autoload :
|
31
|
-
autoload :Findable, 'rsolr-ext/findable.rb'
|
32
|
-
autoload :Doc, 'rsolr-ext/doc.rb'
|
33
|
-
|
34
|
-
# RSolr::Ext.map_params({})
|
35
|
-
def self.map_params(r)
|
36
|
-
RSolr::Ext::Request::Standard.new.map(r)
|
37
|
-
end
|
38
|
-
|
39
|
-
# RSolr::Ext.wrap_response({})
|
40
|
-
def self.wrap_response(r)
|
41
|
-
RSolr::Ext::Response::Standard.new(r)
|
42
|
-
end
|
30
|
+
autoload :Model, 'rsolr-ext/model.rb'
|
43
31
|
|
44
32
|
# c = RSolr::Ext.connect
|
45
33
|
# c.find(:q=>'*:*').docs.size
|
46
34
|
def self.connect(*args)
|
47
35
|
connection = RSolr.connect(*args)
|
48
|
-
connection.extend RSolr::Ext::
|
36
|
+
connection.extend RSolr::Ext::Connection
|
49
37
|
connection
|
50
38
|
end
|
51
39
|
|
data/rsolr-ext.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "rsolr-ext"
|
3
|
-
s.version = "0.
|
4
|
-
s.date = "2009-
|
3
|
+
s.version = "0.8.0"
|
4
|
+
s.date = "2009-07-31"
|
5
5
|
s.summary = "An extension lib for RSolr"
|
6
6
|
s.email = "goodieboy@gmail.com"
|
7
7
|
s.homepage = "http://github.com/mwmitchell/rsolr_ext"
|
@@ -12,13 +12,12 @@ Gem::Specification.new do |s|
|
|
12
12
|
|
13
13
|
"lib/mash.rb",
|
14
14
|
|
15
|
-
"lib/rsolr-ext/
|
15
|
+
"lib/rsolr-ext/connection.rb",
|
16
16
|
|
17
|
-
"lib/rsolr-ext/
|
17
|
+
"lib/rsolr-ext/doc.rb",
|
18
18
|
|
19
|
-
"lib/rsolr-ext/
|
19
|
+
"lib/rsolr-ext/model.rb",
|
20
20
|
|
21
|
-
"lib/rsolr-ext/request/queryable.rb",
|
22
21
|
"lib/rsolr-ext/request.rb",
|
23
22
|
|
24
23
|
"lib/rsolr-ext/response/docs.rb",
|
@@ -34,7 +33,7 @@ Gem::Specification.new do |s|
|
|
34
33
|
"rsolr-ext.gemspec"
|
35
34
|
]
|
36
35
|
s.test_files = [
|
37
|
-
'test/
|
36
|
+
'test/connection_test.rb',
|
38
37
|
'test/request_test.rb',
|
39
38
|
'test/response_test.rb',
|
40
39
|
'test/test_unit_test_case.rb',
|
@@ -2,7 +2,7 @@ require 'test_unit_test_case'
|
|
2
2
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'rsolr-ext')
|
3
3
|
require 'helper'
|
4
4
|
|
5
|
-
class
|
5
|
+
class RSolrExtConnectionTest < Test::Unit::TestCase
|
6
6
|
|
7
7
|
test 'RSolr::connect' do
|
8
8
|
connection = RSolr::Ext.connect
|
data/test/request_test.rb
CHANGED
@@ -1,18 +1,26 @@
|
|
1
1
|
require 'test_unit_test_case'
|
2
2
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'rsolr-ext')
|
3
3
|
|
4
|
+
class Symbol
|
5
|
+
|
6
|
+
def method_missing n,&b
|
7
|
+
[self, n].join('.').to_sym
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
4
12
|
class RSolrExtRequestTest < Test::Unit::TestCase
|
5
13
|
|
6
14
|
test 'standard request' do
|
7
|
-
|
8
|
-
solr_params = std.map(
|
15
|
+
solr_params = RSolr::Ext::Request.map(
|
9
16
|
:page=>2,
|
10
17
|
:per_page=>10,
|
11
18
|
:phrases=>{:name=>'This is a phrase'},
|
12
19
|
:filters=>['test', {:price=>(1..10)}],
|
13
20
|
:phrase_filters=>{:manu=>['Apple']},
|
14
21
|
:queries=>'ipod',
|
15
|
-
:facets=>{:fields=>['cat', 'blah']}
|
22
|
+
:facets=>{:fields=>['cat', 'blah']},
|
23
|
+
:spellcheck => true
|
16
24
|
)
|
17
25
|
assert_equal ["test", "price:[1 TO 10]", "manu:\"Apple\""], solr_params[:fq]
|
18
26
|
assert_equal 10, solr_params[:start]
|
@@ -23,8 +31,7 @@ class RSolrExtRequestTest < Test::Unit::TestCase
|
|
23
31
|
end
|
24
32
|
|
25
33
|
test 'fq param using the phrase_filters mapping' do
|
26
|
-
|
27
|
-
solr_params = std.map(
|
34
|
+
solr_params = RSolr::Ext::Request.map(
|
28
35
|
:phrase_filters=>{:manu=>['Apple', 'ASG'], :color=>['red', 'blue']}
|
29
36
|
)
|
30
37
|
expected = {:fq=>["color:\"red\"", "color:\"blue\"", "manu:\"Apple\"", "manu:\"ASG\""]}
|
data/test/response_test.rb
CHANGED
@@ -13,7 +13,7 @@ class RSolrExtResponseTest < Test::Unit::TestCase
|
|
13
13
|
|
14
14
|
test 'standard response class' do
|
15
15
|
raw_response = eval(mock_query_response)
|
16
|
-
r = RSolr::Ext::Response::
|
16
|
+
r = RSolr::Ext::Response::Base.new(raw_response)
|
17
17
|
assert r.respond_to?(:response)
|
18
18
|
assert r.ok?
|
19
19
|
assert_equal 11, r.docs.size
|
@@ -27,7 +27,7 @@ class RSolrExtResponseTest < Test::Unit::TestCase
|
|
27
27
|
|
28
28
|
test 'standard response doc ext methods' do
|
29
29
|
raw_response = eval(mock_query_response)
|
30
|
-
r = RSolr::Ext::Response::
|
30
|
+
r = RSolr::Ext::Response::Base.new(raw_response)
|
31
31
|
doc = r.docs.first
|
32
32
|
assert doc.has?(:cat, /^elec/)
|
33
33
|
assert ! doc.has?(:cat, 'elec')
|
@@ -40,7 +40,7 @@ class RSolrExtResponseTest < Test::Unit::TestCase
|
|
40
40
|
|
41
41
|
test 'Response::Standard facets' do
|
42
42
|
raw_response = eval(mock_query_response)
|
43
|
-
r = RSolr::Ext::Response::
|
43
|
+
r = RSolr::Ext::Response::Base.new(raw_response)
|
44
44
|
assert_equal 2, r.facets.size
|
45
45
|
|
46
46
|
field_names = r.facets.collect{|facet|facet.name}
|
@@ -68,7 +68,7 @@ class RSolrExtResponseTest < Test::Unit::TestCase
|
|
68
68
|
|
69
69
|
test 'response::standard facet_by_field_name' do
|
70
70
|
raw_response = eval(mock_query_response)
|
71
|
-
r = RSolr::Ext::Response::
|
71
|
+
r = RSolr::Ext::Response::Base.new(raw_response)
|
72
72
|
facet = r.facet_by_field_name('cat')
|
73
73
|
assert_equal 'cat', facet.name
|
74
74
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mwmitchell-rsolr-ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Mitchell
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-31 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -24,10 +24,9 @@ extra_rdoc_files:
|
|
24
24
|
- README.rdoc
|
25
25
|
files:
|
26
26
|
- lib/mash.rb
|
27
|
+
- lib/rsolr-ext/connection.rb
|
27
28
|
- lib/rsolr-ext/doc.rb
|
28
|
-
- lib/rsolr-ext/
|
29
|
-
- lib/rsolr-ext/mapable.rb
|
30
|
-
- lib/rsolr-ext/request/queryable.rb
|
29
|
+
- lib/rsolr-ext/model.rb
|
31
30
|
- lib/rsolr-ext/request.rb
|
32
31
|
- lib/rsolr-ext/response/docs.rb
|
33
32
|
- lib/rsolr-ext/response/facets.rb
|
@@ -39,6 +38,7 @@ files:
|
|
39
38
|
- rsolr-ext.gemspec
|
40
39
|
has_rdoc: true
|
41
40
|
homepage: http://github.com/mwmitchell/rsolr_ext
|
41
|
+
licenses:
|
42
42
|
post_install_message:
|
43
43
|
rdoc_options: []
|
44
44
|
|
@@ -59,12 +59,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
59
|
requirements: []
|
60
60
|
|
61
61
|
rubyforge_project:
|
62
|
-
rubygems_version: 1.
|
62
|
+
rubygems_version: 1.3.5
|
63
63
|
signing_key:
|
64
64
|
specification_version: 2
|
65
65
|
summary: An extension lib for RSolr
|
66
66
|
test_files:
|
67
|
-
- test/
|
67
|
+
- test/connection_test.rb
|
68
68
|
- test/request_test.rb
|
69
69
|
- test/response_test.rb
|
70
70
|
- test/test_unit_test_case.rb
|
data/lib/rsolr-ext/mapable.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
# A module that provides method mapping capabilities.
|
2
|
-
# The basic idea is to pass in a hash to the #map method,
|
3
|
-
# the map method then goes through a list of keys (MAPPED_PARAMS) to
|
4
|
-
# be processed. Each key name can match a key in the input hash.
|
5
|
-
# If there is a match, a method by the name of "map_#{key}" is
|
6
|
-
# called with the following args: input[key], output_hash
|
7
|
-
# The method is responsible for processing the value.
|
8
|
-
# The return value from the method is not used.
|
9
|
-
#
|
10
|
-
# For example: if the mapped params list has :query,
|
11
|
-
# there should be a method like: map_query(input_value, output_hash)
|
12
|
-
# The output_hash is the final hash the the #map method returns,
|
13
|
-
# so whatever you do to output_hash gets returned in the end.
|
14
|
-
module RSolr::Ext::Mapable
|
15
|
-
|
16
|
-
# accepts an input hash.
|
17
|
-
# prepares a return hash by copying the input.
|
18
|
-
# runs through all of the keys in MAPPED_PARAMS.
|
19
|
-
# calls any mapper methods that match the current key in MAPPED_PARAMS.
|
20
|
-
# The mapped keys from the input hash are deleted.
|
21
|
-
# returns a new hash.
|
22
|
-
def map(input)
|
23
|
-
result = input.dup
|
24
|
-
self.class::MAPPED_PARAMS.each do |meth|
|
25
|
-
input_value = result.delete(meth)
|
26
|
-
next if input_value.to_s.empty?
|
27
|
-
send("map_#{meth}", input_value, result)
|
28
|
-
end
|
29
|
-
result
|
30
|
-
end
|
31
|
-
|
32
|
-
# creates an array where the "existing_value" param is first
|
33
|
-
# and the "new_value" is the last.
|
34
|
-
# All empty/nil items are removed.
|
35
|
-
# the return result is either the result of the
|
36
|
-
# array being joined on a space, or the array itself.
|
37
|
-
# "auto_join" should be true or false.
|
38
|
-
def append_to_param(existing_value, new_value, auto_join=true)
|
39
|
-
values = [existing_value, new_value]
|
40
|
-
values.delete_if{|v|v.nil?}
|
41
|
-
auto_join ? values.join(' ') : values.flatten
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# a module to help the creation of solr queries.
|
2
|
-
module RSolr::Ext::Request::Queryable
|
3
|
-
|
4
|
-
# Wraps a string around double quotes
|
5
|
-
def quote(value)
|
6
|
-
%("#{value}")
|
7
|
-
end
|
8
|
-
|
9
|
-
# builds a solr range query from a Range object
|
10
|
-
def build_range(r)
|
11
|
-
"[#{r.min} TO #{r.max}]"
|
12
|
-
end
|
13
|
-
|
14
|
-
# builds a solr query fragment
|
15
|
-
# if "quote_string" is true, the values will be quoted.
|
16
|
-
# if "value" is a string/symbol, the #to_s method is called
|
17
|
-
# if the "value" is an array, each item in the array is
|
18
|
-
# send to build_query (recursive)
|
19
|
-
# if the "value" is a Hash, a fielded query is built
|
20
|
-
# where the keys are used as the field names and
|
21
|
-
# the values are either processed as a Range or
|
22
|
-
# passed back into build_query (recursive)
|
23
|
-
def build_query(value, quote_string=false)
|
24
|
-
case value
|
25
|
-
when String,Symbol
|
26
|
-
quote_string ? quote(value.to_s) : value.to_s
|
27
|
-
when Array
|
28
|
-
value.collect do |v|
|
29
|
-
build_query(v, quote_string)
|
30
|
-
end.flatten
|
31
|
-
when Hash
|
32
|
-
return value.collect do |(k,v)|
|
33
|
-
if v.is_a?(Range)
|
34
|
-
"#{k}:#{build_range(v)}"
|
35
|
-
# If the value is an array, we want the same param, multiple times (not a query join)
|
36
|
-
elsif v.is_a?(Array)
|
37
|
-
v.collect do |vv|
|
38
|
-
"#{k}:#{build_query(vv, quote_string)}"
|
39
|
-
end
|
40
|
-
else
|
41
|
-
"#{k}:#{build_query(v, quote_string)}"
|
42
|
-
end
|
43
|
-
end.flatten
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|