sunspot_stat 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 40d727eb2de555417b4261763ac814f7187c0af8ca7a76e516a5352167c58890
4
+ data.tar.gz: 2bb4e8d14181b8c4bf2fbe40e18bec2f5b2a3c9d5508d1b055bd04b580930838
5
+ SHA512:
6
+ metadata.gz: c92b7a2fd614dacda57177b1f1a134fc449088c307d2f9eaa72a94e30ff7de25c6d98ae897fe4f1131b7e8521a36314f0d287d47b430116a9a6cd030e7022b68
7
+ data.tar.gz: fd689b14bf56bca7c227fa64583c3227382ce6624e40bb1caf35a86023b7f7484f4ec44c661745b88810689f75bfd5887a15ca645919ff2a01967a4494e8d8fa
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sunspot_stat.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Duccio Giovannelli
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Sunspot Stats
2
+
3
+ Sunspot is a Ruby library for expressive, powerful interaction with the Solr search engine. I use the latest version [3.4.1](http://rubygems.org/gems/sunspot/versions/2.1.0) but i need the statsComponent in order to get the sum (min, max, count, sumOfSquares, mean, stddev) on a given indexed field.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'sunspot_stat'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install sunspot_stat
18
+
19
+ ## Usage
20
+
21
+ The statComponent let you to have *min*, *max*, *count*, *missing*, *sum*, *sumOfsquare*, *mean* and *stdev*.
22
+
23
+ ### An usage example
24
+
25
+ ```ruby
26
+ Model.search do
27
+ #Filters
28
+ ...
29
+ #Facets
30
+ ...
31
+ #Stats
32
+ stat(:your_field, :facet => :your_facet_filed, :type => "min")
33
+ ...
34
+ end
35
+ ```
36
+
37
+ **:facet** and **:type** are optional the default type is the "sum" (you can pass: *min*, *max*, *count*, *missing*, *sum*, *sumOfsquare*, *mean*, *stdev* as string)
38
+
39
+ Remember to stats on a non multi valued field and update to the solr3.6, because the solr3.5 has a bug with stats.
40
+
41
+ the Sunspot::SearchStatRow has the method *stat_field* and the *value*.
42
+
43
+ If you enable faceting on stats the stat_field is the facet and the value is the type defined.
44
+
45
+ [Upgrade solr in sunspot](https://github.com/sunspot/sunspot/wiki/Upgrading-sunspot_solr-Solr-Instance)
46
+
47
+
48
+ ### StatsComponent Notes
49
+
50
+ The facet field can be selectively applied. That is if you want stats on field "A" and "B", you can facet a on "X" and B on "Y" using &stats.field=A&f.A.stats.facet=X&stats.field=B&f.B.stats.facet=Y
51
+
52
+ *Warning*, as implemented, all facet results are returned, be careful what fields you ask for!
53
+
54
+ Multi-valued fields and facets may be slow.
55
+
56
+ [StatsComponent](http://wiki.apache.org/solr/StatsComponent)
57
+
58
+ ## Contributing
59
+
60
+ 1. Fork it
61
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
62
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
63
+ 4. Push to the branch (`git push origin my-new-feature`)
64
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ module Sunspot
2
+ module DSL
3
+ #
4
+ # Provides an API for areas of the query DSL that operate on specific
5
+ # fields. This functionality is provided by the query DSL and the dynamic
6
+ # query DSL.
7
+ #
8
+ class FieldQuery < Scope
9
+ def initialize(search, query, setup) #:nodoc:
10
+ @search, @query = search, query
11
+ super(query.scope, setup)
12
+ end
13
+
14
+ def stat(field_name, options = {})
15
+ field = @setup.field(field_name)
16
+ options[:facet] = @setup.field(options[:facet]) if !options[:facet].nil?
17
+ stat = @query.add_stat(Sunspot::Query::FieldStat.new(field, options))
18
+ @search.add_field_stat(field, options)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ module Sunspot
2
+ module Query
3
+ #
4
+ # A FieldStat stats by the unique values of a given field.
5
+ #
6
+ class FieldStat
7
+
8
+ def initialize(field, options = {})
9
+ if field.multiple?
10
+ raise(ArgumentError, "#{field.name} cannot be used for stats because it is a multiple-value field")
11
+ end
12
+ @field = field
13
+ @options = options
14
+ @sort = SortComposite.new
15
+ end
16
+
17
+ def add_sort(sort)
18
+ @sort << sort
19
+ end
20
+
21
+ def to_params
22
+ params = {
23
+ :stats => 'true',
24
+ :"stats.field" => @field.indexed_name
25
+ }
26
+ params.merge!({:"stats.facet" => @options[:facet].indexed_name}) if !@options[:facet].nil?
27
+ params
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ module Sunspot
2
+ module Query #:nodoc:
3
+ class CommonQuery
4
+
5
+ def add_stat(stat)
6
+ @components << stat
7
+ stat
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,50 @@
1
+ module Sunspot
2
+ module Search
3
+ class StatFacet
4
+
5
+ def initialize(field, search, options)
6
+ @field, @search, @options = field, search, options
7
+ end
8
+
9
+ def field_name
10
+ @field.name
11
+ end
12
+
13
+ def rows
14
+ #sort options :count or :stat_field
15
+ @options[:sort] ||= :count
16
+ @options[:type] ||= "sum"
17
+ @options[:limit] ||= -1
18
+ @sort = false
19
+ @rows ||=
20
+ begin
21
+ if @search.stat_response.present? && @search.stat_response['stats_fields'].present?
22
+ if @options[:facet].present?
23
+ stat = @search.stat_response['stats_fields'][@field.indexed_name]
24
+ data = stat.nil? ? [] : stat['facets'][@options[:facet].indexed_name]
25
+ @sort = true
26
+ else
27
+ data = @search.stat_response['stats_fields'].to_a
28
+ end
29
+ end
30
+
31
+ rows = []
32
+
33
+ data.collect do |stat, value|
34
+ rows << StatRow.new(stat, value[@options[:type]], value, self) if value.present?
35
+ end
36
+
37
+ if @options[:sort] == :count
38
+ rows.sort! { |lrow, rrow| rrow.value <=> lrow.value }
39
+ else
40
+ rows.sort! { |lrow, rrow| lrow.stat_field <=> rrow.stat_field }
41
+ end if @sort
42
+ rows.empty? ? [] : rows[0..@options[:limit]]
43
+ rescue Exception => e
44
+ puts "Sunspot Stats error: #{e.message} \n\n #{e.backtrace}"
45
+ return []
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ module Sunspot
2
+ module Search
3
+ class StatRow
4
+ attr_reader :stat_field, :value, :all_values
5
+ attr_writer :instance #:nodoc:
6
+
7
+ def initialize(stat_field, value, all_values, stat) #:nodoc:
8
+ @stat_field, @value, @all_values, @stat = stat_field, value, all_values, stat
9
+ end
10
+
11
+ #
12
+ # Return the instance referenced by this stat row. Only valid for field
13
+ # stats whose fields are defined with the :references key.
14
+ #
15
+
16
+ def instance
17
+ if !defined?(@instance)
18
+ @stat.populate_instances
19
+ end
20
+ @instance
21
+ end
22
+
23
+ def inspect
24
+ "<Sunspot::Search::StatRow:#{stat_field.inspect} (#{value} - #{all_values})>"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,68 @@
1
+ require 'sunspot/search/paginated_collection'
2
+ require 'sunspot/search/hit_enumerable'
3
+
4
+ module Sunspot
5
+ module Search #:nodoc:
6
+
7
+ #
8
+ # This class encapsulates the results of a Solr search. It provides access
9
+ # to search results, total result count, facets, and pagination information.
10
+ # Instances of Search are returned by the Sunspot.search and
11
+ # Sunspot.new_search methods.
12
+ #
13
+ class AbstractSearch
14
+ #
15
+ # Retrieve all facet objects defined for this search, in order they were
16
+ # defined. To retrieve an individual facet by name, use #facet()
17
+ #
18
+ attr_reader :stats
19
+
20
+ def initialize(connection, setup, query, configuration) #:nodoc:
21
+ @connection, @setup, @query = connection, setup, query
22
+ @query.paginate(1, configuration.pagination.default_per_page)
23
+
24
+ @stats = []
25
+ @stats_by_name = {}
26
+
27
+ @facets = []
28
+ @facets_by_name = {}
29
+
30
+ @groups_by_name = {}
31
+ @groups = []
32
+ end
33
+
34
+
35
+ def stat(name)
36
+ if name
37
+ @stats_by_name[name.to_sym]
38
+ end
39
+ end
40
+
41
+ def stat_response #:nodoc:
42
+ @solr_result['stats']["stats_fields"].each_pair do |k, value|
43
+ if value && value.key?("facets")
44
+ value["facets"].each_pair do |k1, value1|
45
+ value1.each_pair do |k2, value2|
46
+ if @solr_result['stats']['stats_fields'][k]['facets'][k1][k2]['mean'].to_s == 'NaN'
47
+ @solr_result['stats']['stats_fields'][k]['facets'][k1][k2]['mean'] = 0.0
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ @solr_result['stats']||[]
54
+ end
55
+
56
+ def add_field_stat(field, options = {}) #:nodoc:
57
+ name = (options[:name] || field.name)
58
+ add_stat(name, StatFacet.new(field, self, options))
59
+ end
60
+
61
+ def add_stat(name, stat)
62
+ @stats << stat
63
+ @stats_by_name[name.to_sym] = stat
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module SunspotStat
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,15 @@
1
+ require "sunspot_stat/version"
2
+
3
+ %w(field_query).each do |file|
4
+ require File.join(File.dirname(__FILE__), "dsl", file)
5
+ end
6
+
7
+
8
+ %w(stat_search stat_row stat_facet).each do |file|
9
+ require File.join(File.dirname(__FILE__), "search", file)
10
+ end
11
+
12
+ %w(stat_query field_stat).each do |file|
13
+ require(File.join(File.dirname(__FILE__), 'query', file))
14
+ end
15
+
@@ -0,0 +1 @@
1
+ require File.expand_path('spec_helper', File.join(File.dirname(__FILE__), '..'))
@@ -0,0 +1,16 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe "stats component" do
4
+
5
+ it "sends stats parameters to solr" do
6
+
7
+ session.search Content do
8
+ stat :visibility, :facet => :published_at
9
+ end
10
+
11
+ connection.should have_last_search_including(:stats, "true")
12
+ connection.should have_last_search_including(:"stats.field", "visibility_f")
13
+ connection.should have_last_search_including(:"stats.facet", "published_at_d")
14
+ end
15
+
16
+ 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_stat'
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
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/sunspot_stat/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["nitin rakesh"]
6
+ gem.email = ["nitinrak.25s@gmail.com"]
7
+ gem.description = <<-TEXT
8
+ Sunspot is a library providing a powerful, all-ruby API for the Solr search engine. This gem extend sunspot adding the
9
+ statsComponent feature, which returns simple statistics for indexed numeric fields within the DocSet.
10
+ TEXT
11
+ gem.summary = "Added the statsComponent to sunspot"
12
+ gem.homepage = "https://github.com/nitinrakesh-332/sunspot_stat"
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "sunspot_stat"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = SunspotStat::VERSION
19
+
20
+ gem.add_development_dependency "rspec"
21
+
22
+ gem.rdoc_options << '--webcvs=http://https://github.com/nitinrakesh-332/sunspot_stat/tree/master/%s' <<
23
+ '--title' << 'Sunspot Stat - StatsComponent for sunspot - API Documentation' <<
24
+ '--main' << 'README.rdoc'
25
+ end
Binary file
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sunspot_stat
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - nitin rakesh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-02-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: " Sunspot is a library providing a powerful, all-ruby API for the
28
+ Solr search engine. This gem extend sunspot adding the \n statsComponent feature,
29
+ which returns simple statistics for indexed numeric fields within the DocSet.\n"
30
+ email:
31
+ - nitinrak.25s@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - Gemfile
37
+ - LICENSE
38
+ - README.md
39
+ - Rakefile
40
+ - lib/dsl/field_query.rb
41
+ - lib/query/field_stat.rb
42
+ - lib/query/stat_query.rb
43
+ - lib/search/stat_facet.rb
44
+ - lib/search/stat_row.rb
45
+ - lib/search/stat_search.rb
46
+ - lib/sunspot_stat/version.rb
47
+ - lib/sunspot_stats.rb
48
+ - spec/api/query/spec_helper.rb
49
+ - spec/api/query/stats_spec.rb
50
+ - spec/api/search/spec_helper.rb
51
+ - spec/api/search/stats_spec.rb
52
+ - spec/api/spec_helper.rb
53
+ - spec/ext.rb
54
+ - spec/helpers/indexer_helper.rb
55
+ - spec/helpers/integration_helper.rb
56
+ - spec/helpers/mock_session_helper.rb
57
+ - spec/helpers/query_helper.rb
58
+ - spec/helpers/search_helper.rb
59
+ - spec/mocks/adapters.rb
60
+ - spec/mocks/connection.rb
61
+ - spec/mocks/content.rb
62
+ - spec/mocks/mock_adapter.rb
63
+ - spec/mocks/mock_record.rb
64
+ - spec/mocks/super_class.rb
65
+ - spec/spec_helper.rb
66
+ - sunspot_stat.gemspec
67
+ - sunspot_stats-0.0.7.gem
68
+ homepage: https://github.com/nitinrakesh-332/sunspot_stat
69
+ licenses: []
70
+ metadata: {}
71
+ post_install_message:
72
+ rdoc_options:
73
+ - "--webcvs=http://https://github.com/nitinrakesh-332/sunspot_stat/tree/master/%s"
74
+ - "--title"
75
+ - Sunspot Stat - StatsComponent for sunspot - API Documentation
76
+ - "--main"
77
+ - README.rdoc
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.5.3
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Added the statsComponent to sunspot
95
+ test_files:
96
+ - spec/api/query/spec_helper.rb
97
+ - spec/api/query/stats_spec.rb
98
+ - spec/api/search/spec_helper.rb
99
+ - spec/api/search/stats_spec.rb
100
+ - spec/api/spec_helper.rb
101
+ - spec/ext.rb
102
+ - spec/helpers/indexer_helper.rb
103
+ - spec/helpers/integration_helper.rb
104
+ - spec/helpers/mock_session_helper.rb
105
+ - spec/helpers/query_helper.rb
106
+ - spec/helpers/search_helper.rb
107
+ - spec/mocks/adapters.rb
108
+ - spec/mocks/connection.rb
109
+ - spec/mocks/content.rb
110
+ - spec/mocks/mock_adapter.rb
111
+ - spec/mocks/mock_record.rb
112
+ - spec/mocks/super_class.rb
113
+ - spec/spec_helper.rb