sunspot_stats 0.0.2 → 0.0.3

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
@@ -50,6 +50,11 @@ Usually Suspot use the dismax for searches, here we extend to edismax to manage
50
50
 
51
51
  a OR (b AND c) works.
52
52
 
53
+ ## TODO
54
+
55
+ Some more test!
56
+
57
+
53
58
  ## Contributing
54
59
 
55
60
  1. Fork it
@@ -13,7 +13,7 @@ module Sunspot
13
13
 
14
14
  def stat(field_name, options = {})
15
15
  field = @setup.field(field_name)
16
- options[:facet] = @setup.field(options[:facet]) if options[:facet].present?
16
+ options[:facet] = @setup.field(options[:facet]) if !options[:facet].nil?
17
17
  stat = @query.add_stat(Sunspot::Query::FieldStat.new(field, options))
18
18
  @search.add_field_stat(field, options)
19
19
  end
@@ -23,7 +23,7 @@ module Sunspot
23
23
  :stats => 'true',
24
24
  :"stats.field" => @field.indexed_name
25
25
  }
26
- params.merge!({:"stats.facet" => @options[:facet].indexed_name}) if @options[:facet].present?
26
+ params.merge!({:"stats.facet" => @options[:facet].indexed_name}) if !@options[:facet].nil?
27
27
  params
28
28
  end
29
29
  end
@@ -1,3 +1,3 @@
1
1
  module SunspotStats
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1 @@
1
+ require File.expand_path('spec_helper', File.join(File.dirname(__FILE__), '..'))
@@ -0,0 +1,14 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe "stats component" do
4
+ it "sends stats parameters to solr" do
5
+ session.search Content do
6
+ stat :visibility, :facet => :published_at
7
+ end
8
+
9
+ connection.should have_last_search_including(:stats, "true")
10
+ connection.should have_last_search_including(:"stats.field", "visibility_f")
11
+ connection.should have_last_search_including(:"stats.facet", "published_at_d")
12
+ end
13
+
14
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path('spec_helper', File.join(File.dirname(__FILE__), '..'))
@@ -0,0 +1,13 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'stats', :type => :search do
4
+ it 'returns field name for facet' do
5
+ #stub_stat(:visibility)
6
+ result = session.search Content do
7
+ stat :visibility, :facet => :published_at
8
+ end
9
+
10
+ result.stat(:visibility).field_name.should == :visibility
11
+ end
12
+
13
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path('spec_helper', File.join(File.dirname(__FILE__), '..'))
2
+
3
+ Dir.glob(File.join(File.dirname(__FILE__), '**', '*_examples.rb')).each { |shared| require(shared) }
data/spec/ext.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Solr
2
+ class Document
3
+ def field_by_name(field_name)
4
+ @fields.find { |field| field.name.to_s == field_name.to_s }
5
+ end
6
+
7
+ def fields_by_name(field_name)
8
+ @fields.select { |field| field.name.to_s == field_name.to_s }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module IndexerHelper
2
+ def post(attrs = {})
3
+ @post ||= Post.new(attrs)
4
+ end
5
+
6
+ def last_add
7
+ @connection.adds.last
8
+ end
9
+
10
+ def value_in_last_document_for(field_name)
11
+ @connection.adds.last.last.field_by_name(field_name).value
12
+ end
13
+
14
+ def values_in_last_document_for(field_name)
15
+ @connection.adds.last.last.fields_by_name(field_name).map { |field| field.value }
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ module IntegrationHelper
2
+ def self.included(base)
3
+ base.before(:all) do
4
+ Sunspot.config.solr.url = ENV['SOLR_URL'] || 'http://localhost:8983/solr'
5
+ Sunspot.reset!(true)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ module MockSessionHelper
2
+ def config
3
+ @config ||= Sunspot::Configuration.build
4
+ end
5
+
6
+ def connection
7
+ @connection ||= Mock::Connection.new
8
+ end
9
+
10
+ def session
11
+ @session ||= Sunspot::Session.new(config, connection)
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ module QueryHelper
2
+ def get_filter_tag(boolean_query)
3
+ connection.searches.last[:fq].each do |fq|
4
+ if match = fq.match(/^\{!tag=(.+)\}#{Regexp.escape(boolean_query)}$/)
5
+ return match[1]
6
+ end
7
+ end
8
+ nil
9
+ end
10
+
11
+ def subqueries(param)
12
+ q = connection.searches.last[:q]
13
+ subqueries = []
14
+ subqueries = q.scan(%r(_query_:"\{!dismax (.*?)\}(.*?)"))
15
+ subqueries.map do |subquery|
16
+ params = {}
17
+ subquery[0].scan(%r((\S+?)='(.+?)')) do |key, value|
18
+ params[key.to_sym] = value
19
+ end
20
+ unless subquery[1].empty?
21
+ params[:v] = subquery[1]
22
+ end
23
+ params
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,55 @@
1
+ module SearchHelper
2
+ def stub_nil_results
3
+ connection.response = { 'response' => nil }
4
+ end
5
+
6
+ def stub_full_results(*results)
7
+ count =
8
+ if results.last.is_a?(Integer) then results.pop
9
+ else results.length
10
+ end
11
+ docs = results.map do |result|
12
+ instance = result.delete('instance')
13
+ result.merge('id' => "#{instance.class.name} #{instance.id}")
14
+ end
15
+ response = {
16
+ 'response' => {
17
+ 'docs' => docs,
18
+ 'numFound' => count
19
+ }
20
+ }
21
+ connection.response = response
22
+ response
23
+ end
24
+
25
+ def stub_results(*results)
26
+ stub_full_results(
27
+ *results.map do |result|
28
+ if result.is_a?(Integer)
29
+ result
30
+ else
31
+ { 'instance' => result }
32
+ end
33
+ end
34
+ )
35
+ end
36
+
37
+ def stub_stat(name, values)
38
+ connection.response = {
39
+ 'facet_counts' => {
40
+ 'facet_fields' => {
41
+ name.to_s => values.to_a.sort_by { |value, count| -count }.flatten
42
+ }
43
+ }
44
+ }
45
+ end
46
+
47
+ def stat_field_name(result, field_name)
48
+ result.stat(field_name).rows.map { |row| row.field_name }
49
+ end
50
+
51
+ def values(result, field_name)
52
+ result.stat(field_name).rows.map { |row| row.value }
53
+ end
54
+
55
+ end
@@ -0,0 +1,32 @@
1
+ class AbstractModel
2
+ end
3
+
4
+ class Model < AbstractModel
5
+ end
6
+
7
+ class AbstractModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
8
+ end
9
+
10
+ class AbstractModelDataAccessor < Sunspot::Adapters::DataAccessor
11
+ end
12
+
13
+ Sunspot::Adapters::InstanceAdapter.register(AbstractModelInstanceAdapter, AbstractModel)
14
+ Sunspot::Adapters::DataAccessor.register(AbstractModelDataAccessor, AbstractModel)
15
+
16
+
17
+ module MixInModel
18
+ end
19
+
20
+ class MixModel
21
+ include MixInModel
22
+ end
23
+
24
+ class MixInModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
25
+ end
26
+
27
+ class MixInModelDataAccessor < Sunspot::Adapters::DataAccessor
28
+ end
29
+
30
+ Sunspot::Adapters::InstanceAdapter.register(MixInModelInstanceAdapter, MixInModel)
31
+ Sunspot::Adapters::DataAccessor.register(MixInModelDataAccessor, MixInModel)
32
+
@@ -0,0 +1,126 @@
1
+ module Mock
2
+ class ConnectionFactory
3
+ def connect(opts)
4
+ if @instance
5
+ raise('Factory can only create an instance once!')
6
+ else
7
+ @instance = Connection.new(opts)
8
+ end
9
+ end
10
+
11
+ def new(url = nil)
12
+ if @instance
13
+ raise('Factory can only create an instance once!')
14
+ else
15
+ @instance = Connection.new(url)
16
+ end
17
+ end
18
+
19
+ def instance
20
+ @instance ||= Connection.new
21
+ end
22
+ end
23
+
24
+ class Connection
25
+ attr_reader :adds, :commits, :optims, :searches, :message, :opts, :deletes_by_query
26
+ attr_accessor :response
27
+ attr_writer :expected_handler
28
+ undef_method :select # annoyingly defined on Object
29
+
30
+ def initialize(opts = {})
31
+ @opts = opts
32
+ @message = OpenStruct.new
33
+ @adds, @deletes, @deletes_by_query, @commits, @optims, @searches = Array.new(6) { [] }
34
+ @expected_handler = :select
35
+ end
36
+
37
+ def add(documents)
38
+ @adds << Array(documents)
39
+ end
40
+
41
+ def delete_by_id(ids)
42
+ @deletes << Array(ids)
43
+ end
44
+
45
+ def delete_by_query(query)
46
+ @deletes_by_query << query
47
+ end
48
+
49
+ def commit
50
+ @commits << Time.now
51
+ end
52
+
53
+ def optimize
54
+ @optims << Time.now
55
+ end
56
+
57
+ def post(path, params)
58
+ unless path == "#{@expected_handler}"
59
+ raise ArgumentError, "Expected request to #{@expected_handler} request handler"
60
+ end
61
+ @searches << @last_search = params[:data]
62
+ @response || {}
63
+ end
64
+
65
+ def method_missing(method, *args, &block)
66
+ get("#{method}", *args)
67
+ end
68
+
69
+ def has_add_with?(*documents)
70
+ @adds.any? do |add|
71
+ documents.all? do |document|
72
+ add.any? do |added|
73
+ if document.is_a?(Hash)
74
+ document.all? do |field, value|
75
+ added.fields_by_name(field).map do |field|
76
+ field.value.to_s
77
+ end == Array(value).map { |v| v.to_s }
78
+ end
79
+ else
80
+ !added.fields_by_name(document).empty?
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def has_delete?(*ids)
88
+ @deletes.any? do |delete|
89
+ delete & ids == ids
90
+ end
91
+ end
92
+
93
+ def has_delete_by_query?(query)
94
+ @deletes_by_query.include?(query)
95
+ end
96
+
97
+ def has_last_search_with?(params)
98
+ with?(@last_search, params) if @last_search
99
+ end
100
+
101
+ def has_last_search_including?(key, *values)
102
+ return unless @last_search
103
+ if @last_search.has_key?(key)
104
+ if @last_search[key].is_a?(Array)
105
+ (@last_search[key] & values).length == values.length
106
+ elsif values.length == 1
107
+ @last_search[key] == values.first
108
+ end
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def with?(request, params)
115
+ if params.respond_to?(:all?)
116
+ params.all? do |key, value|
117
+ if request.has_key?(key)
118
+ request[key] == value
119
+ end
120
+ end
121
+ else
122
+ request.has_key?(params)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), 'super_class')
2
+
3
+ class Content < SuperClass
4
+ attr_accessor :body, :visibility, :published_at
5
+ end
6
+
7
+ Sunspot.setup(Content) do
8
+ text :body
9
+ float :visibility
10
+ time :published_at
11
+ end
12
+
@@ -0,0 +1,30 @@
1
+ require File.join(File.dirname(__FILE__), 'content')
2
+
3
+ module MockAdapter
4
+ class InstanceAdapter < Sunspot::Adapters::InstanceAdapter
5
+ def id
6
+ @instance.id
7
+ end
8
+ end
9
+
10
+ class DataAccessor < Sunspot::Adapters::DataAccessor
11
+ def load(id)
12
+ @clazz.get(id.to_i)
13
+ end
14
+
15
+ def load_all(ids)
16
+ all = @clazz.get_all(ids.map { |id| id.to_i })
17
+ if @custom_title
18
+ all.each { |item| item.title = @custom_title }
19
+ end
20
+ all
21
+ end
22
+
23
+ def custom_title=(custom_title)
24
+ @custom_title = custom_title
25
+ end
26
+ end
27
+ end
28
+
29
+ Sunspot::Adapters::DataAccessor.register(MockAdapter::DataAccessor, MockRecord)
30
+ Sunspot::Adapters::InstanceAdapter.register(MockAdapter::InstanceAdapter, MockRecord)
@@ -0,0 +1,52 @@
1
+ class MockRecord
2
+ IDS = Hash.new { |h, k| h[k] = 0 }
3
+ QUERY_COUNTS = Hash.new { |h, k| h[k] = 0 }
4
+ INSTANCES = Hash.new { |h, k| h[k] = {} }
5
+
6
+ attr_reader :id
7
+
8
+ class <<self
9
+ def reset!
10
+ IDS[name.to_sym] = 0
11
+ INSTANCES[name.to_sym] = {}
12
+ end
13
+ end
14
+
15
+ def initialize(attrs = {})
16
+ @id = attrs.delete(:id) || IDS[self.class.name.to_sym] += 1
17
+ INSTANCES[self.class.name.to_sym][@id] = self
18
+ attrs.each_pair do |name, value|
19
+ send(:"#{name}=", value)
20
+ end
21
+ end
22
+
23
+ def self.inherited(base)
24
+ base.extend(ClassMethods)
25
+ end
26
+
27
+ module ClassMethods
28
+ def get(id)
29
+ QUERY_COUNTS[self.name.to_sym] += 1
30
+ get_instance(id)
31
+ end
32
+
33
+ def get_all(ids)
34
+ QUERY_COUNTS[self.name.to_sym] += 1
35
+ ids.map { |id| get_instance(id) }.compact.sort_by { |instance| instance.id }
36
+ end
37
+
38
+ def query_count
39
+ QUERY_COUNTS[self.name.to_sym]
40
+ end
41
+
42
+ private
43
+
44
+ def get_instance(id)
45
+ INSTANCES[self.name.to_sym][id]
46
+ end
47
+ end
48
+
49
+ def destroy
50
+ INSTANCES[self.class.name.to_sym].delete(@id)
51
+ end
52
+ end
@@ -0,0 +1,2 @@
1
+ class SuperClass < MockRecord
2
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'ostruct'
4
+ require 'sunspot'
5
+ require 'sunspot_stats'
6
+
7
+ require File.join(File.dirname(__FILE__), 'mocks', 'mock_record.rb')
8
+ Dir.glob(File.join(File.dirname(__FILE__), 'mocks', '**', '*.rb')).each do |file|
9
+ require file unless File.basename(file) == 'mock_record.rb'
10
+ end
11
+ Dir.glob(File.join(File.dirname(__FILE__), "helpers", "*.rb")).each do |file|
12
+ require file
13
+ end
14
+ require File.join(File.dirname(__FILE__), 'ext')
15
+
16
+ RSpec.configure do |config|
17
+ # Mock session available to all spec/api tests
18
+ config.include MockSessionHelper,
19
+ :type => :api,
20
+ :example_group => {:file_path => /spec[\\\/]api/}
21
+
22
+ # Real Solr instance is available to integration tests
23
+ config.include IntegrationHelper,
24
+ :type => :integration,
25
+ :example_group => {:file_path => /spec[\\\/]integration/}
26
+
27
+ # Nested under spec/api
28
+ [:indexer, :query, :search].each do |spec_type|
29
+ helper_name = "#{spec_type}_helper"
30
+
31
+ config.include Sunspot::Util.full_const_get(Sunspot::Util.camel_case(helper_name)),
32
+ :type => spec_type,
33
+ :example_group => {:file_path => /spec[\\\/]api[\\\/]#{spec_type}/}
34
+ end
35
+ end
36
+
37
+ def without_class(clazz)
38
+ Object.class_eval { remove_const(clazz.name.to_sym) }
39
+ yield
40
+ Object.class_eval { const_set(clazz.name.to_sym, clazz) }
41
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - duccio giovannelli
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-07-14 00:00:00 +02:00
17
+ date: 2012-07-16 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -69,6 +69,24 @@ files:
69
69
  - lib/search/stat_search.rb
70
70
  - lib/sunspot_stats.rb
71
71
  - lib/sunspot_stats/version.rb
72
+ - spec/api/query/spec_helper.rb
73
+ - spec/api/query/stats_spec.rb
74
+ - spec/api/search/spec_helper.rb
75
+ - spec/api/search/stats_spec.rb
76
+ - spec/api/spec_helper.rb
77
+ - spec/ext.rb
78
+ - spec/helpers/indexer_helper.rb
79
+ - spec/helpers/integration_helper.rb
80
+ - spec/helpers/mock_session_helper.rb
81
+ - spec/helpers/query_helper.rb
82
+ - spec/helpers/search_helper.rb
83
+ - spec/mocks/adapters.rb
84
+ - spec/mocks/connection.rb
85
+ - spec/mocks/content.rb
86
+ - spec/mocks/mock_adapter.rb
87
+ - spec/mocks/mock_record.rb
88
+ - spec/mocks/super_class.rb
89
+ - spec/spec_helper.rb
72
90
  - sunspot_stats.gemspec
73
91
  has_rdoc: true
74
92
  homepage: https://github.com/giovannelli/sunspot_stats
@@ -104,5 +122,22 @@ rubygems_version: 1.3.6
104
122
  signing_key:
105
123
  specification_version: 3
106
124
  summary: Added the statsComponent to sunspot
107
- test_files: []
108
-
125
+ test_files:
126
+ - spec/api/query/spec_helper.rb
127
+ - spec/api/query/stats_spec.rb
128
+ - spec/api/search/spec_helper.rb
129
+ - spec/api/search/stats_spec.rb
130
+ - spec/api/spec_helper.rb
131
+ - spec/ext.rb
132
+ - spec/helpers/indexer_helper.rb
133
+ - spec/helpers/integration_helper.rb
134
+ - spec/helpers/mock_session_helper.rb
135
+ - spec/helpers/query_helper.rb
136
+ - spec/helpers/search_helper.rb
137
+ - spec/mocks/adapters.rb
138
+ - spec/mocks/connection.rb
139
+ - spec/mocks/content.rb
140
+ - spec/mocks/mock_adapter.rb
141
+ - spec/mocks/mock_record.rb
142
+ - spec/mocks/super_class.rb
143
+ - spec/spec_helper.rb