DrMark-thinking-sphinx 1.1.15 → 1.2.5
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.textile +22 -0
- data/VERSION.yml +4 -0
- data/lib/thinking_sphinx/active_record/scopes.rb +39 -0
- data/lib/thinking_sphinx/active_record.rb +27 -7
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +9 -3
- data/lib/thinking_sphinx/association.rb +4 -1
- data/lib/thinking_sphinx/attribute.rb +91 -30
- data/lib/thinking_sphinx/configuration.rb +51 -12
- data/lib/thinking_sphinx/deltas/datetime_delta.rb +2 -2
- data/lib/thinking_sphinx/deltas/default_delta.rb +1 -1
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +3 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +25 -8
- data/lib/thinking_sphinx/excerpter.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +1 -1
- data/lib/thinking_sphinx/facet_search.rb +134 -0
- data/lib/thinking_sphinx/index.rb +2 -1
- data/lib/thinking_sphinx/rails_additions.rb +14 -0
- data/lib/thinking_sphinx/search.rb +599 -658
- data/lib/thinking_sphinx/search_methods.rb +421 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +1 -1
- data/lib/thinking_sphinx/source/sql.rb +17 -13
- data/lib/thinking_sphinx/source.rb +6 -6
- data/lib/thinking_sphinx/tasks.rb +42 -8
- data/lib/thinking_sphinx.rb +82 -54
- data/rails/init.rb +14 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +5 -5
- data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +96 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +51 -31
- data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
- data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
- data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +161 -29
- data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
- data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/{unit → lib}/thinking_sphinx/facet_spec.rb +24 -0
- data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +8 -8
- data/spec/{unit → lib}/thinking_sphinx/index/builder_spec.rb +6 -2
- data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/index_spec.rb +45 -0
- data/spec/{unit → lib}/thinking_sphinx/rails_additions_spec.rb +25 -5
- data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
- data/spec/lib/thinking_sphinx/search_spec.rb +960 -0
- data/spec/{unit → lib}/thinking_sphinx/source_spec.rb +63 -2
- data/spec/{unit → lib}/thinking_sphinx_spec.rb +32 -4
- data/tasks/distribution.rb +36 -35
- data/vendor/riddle/lib/riddle/client/message.rb +4 -3
- data/vendor/riddle/lib/riddle/client.rb +3 -0
- data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
- data/vendor/riddle/lib/riddle/controller.rb +17 -7
- data/vendor/riddle/lib/riddle.rb +1 -1
- metadata +79 -83
- data/lib/thinking_sphinx/active_record/search.rb +0 -57
- data/lib/thinking_sphinx/collection.rb +0 -148
- data/lib/thinking_sphinx/facet_collection.rb +0 -59
- data/lib/thinking_sphinx/search/facets.rb +0 -98
- data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
- data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -232
- data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
- data/spec/unit/thinking_sphinx/facet_collection_spec.rb +0 -64
- data/spec/unit/thinking_sphinx/index_spec.rb +0 -139
- data/spec/unit/thinking_sphinx/search_spec.rb +0 -130
@@ -1,148 +0,0 @@
|
|
1
|
-
module ThinkingSphinx
|
2
|
-
class Collection < ::Array
|
3
|
-
attr_reader :total_entries, :total_pages, :current_page, :per_page
|
4
|
-
attr_accessor :results
|
5
|
-
|
6
|
-
# Compatibility with older versions of will_paginate
|
7
|
-
alias_method :page_count, :total_pages
|
8
|
-
|
9
|
-
def initialize(page, per_page, entries, total_entries)
|
10
|
-
@current_page, @per_page, @total_entries = page, per_page, total_entries
|
11
|
-
|
12
|
-
@total_pages = (entries / @per_page.to_f).ceil
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.ids_from_results(results, page, limit, options)
|
16
|
-
collection = self.new(page, limit,
|
17
|
-
results[:total] || 0, results[:total_found] || 0
|
18
|
-
)
|
19
|
-
collection.results = results
|
20
|
-
collection.replace results[:matches].collect { |match|
|
21
|
-
match[:attributes]["sphinx_internal_id"]
|
22
|
-
}
|
23
|
-
return collection
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.create_from_results(results, page, limit, options)
|
27
|
-
collection = self.new(page, limit,
|
28
|
-
results[:total] || 0, results[:total_found] || 0
|
29
|
-
)
|
30
|
-
collection.results = results
|
31
|
-
collection.replace instances_from_matches(results[:matches], options)
|
32
|
-
return collection
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.instances_from_matches(matches, options = {})
|
36
|
-
if klass = options[:class]
|
37
|
-
instances_from_class klass, matches, options
|
38
|
-
else
|
39
|
-
instances_from_classes matches, options
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.instances_from_class(klass, matches, options = {})
|
44
|
-
index_options = klass.sphinx_index_options
|
45
|
-
|
46
|
-
ids = matches.collect { |match| match[:attributes]["sphinx_internal_id"] }
|
47
|
-
instances = ids.length > 0 ? klass.find(
|
48
|
-
:all,
|
49
|
-
:joins => options[:joins],
|
50
|
-
:conditions => {klass.primary_key.to_sym => ids},
|
51
|
-
:include => (options[:include] || index_options[:include]),
|
52
|
-
:select => (options[:select] || index_options[:select]),
|
53
|
-
:order => (options[:sql_order] || index_options[:sql_order])
|
54
|
-
) : []
|
55
|
-
|
56
|
-
# Raise an exception if we find records in Sphinx but not in the DB, so
|
57
|
-
# the search method can retry without them. See
|
58
|
-
# ThinkingSphinx::Search.retry_search_on_stale_index.
|
59
|
-
if options[:raise_on_stale] && instances.length < ids.length
|
60
|
-
stale_ids = ids - instances.map {|i| i.id }
|
61
|
-
raise StaleIdsException, stale_ids
|
62
|
-
end
|
63
|
-
|
64
|
-
# if the user has specified an SQL order, return the collection
|
65
|
-
# without rearranging it into the Sphinx order
|
66
|
-
return instances if options[:sql_order]
|
67
|
-
|
68
|
-
ids.collect { |obj_id|
|
69
|
-
instances.detect { |obj| obj.id == obj_id }
|
70
|
-
}
|
71
|
-
end
|
72
|
-
|
73
|
-
# Group results by class and call #find(:all) once for each group to reduce
|
74
|
-
# the number of #find's in multi-model searches.
|
75
|
-
#
|
76
|
-
def self.instances_from_classes(matches, options = {})
|
77
|
-
groups = matches.group_by { |match| match[:attributes]["class_crc"] }
|
78
|
-
groups.each do |crc, group|
|
79
|
-
group.replace(
|
80
|
-
instances_from_class(class_from_crc(crc), group, options)
|
81
|
-
)
|
82
|
-
end
|
83
|
-
|
84
|
-
matches.collect do |match|
|
85
|
-
groups.detect { |crc, group|
|
86
|
-
crc == match[:attributes]["class_crc"]
|
87
|
-
}[1].detect { |obj|
|
88
|
-
obj.id == match[:attributes]["sphinx_internal_id"]
|
89
|
-
}
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.class_from_crc(crc)
|
94
|
-
@@models_by_crc ||= ThinkingSphinx.indexed_models.inject({}) do |hash, model|
|
95
|
-
hash[model.constantize.to_crc32] = model
|
96
|
-
model.constantize.subclasses.each { |subclass|
|
97
|
-
hash[subclass.to_crc32] = subclass.name
|
98
|
-
}
|
99
|
-
hash
|
100
|
-
end
|
101
|
-
@@models_by_crc[crc].constantize
|
102
|
-
end
|
103
|
-
|
104
|
-
def previous_page
|
105
|
-
current_page > 1 ? (current_page - 1) : nil
|
106
|
-
end
|
107
|
-
|
108
|
-
def next_page
|
109
|
-
current_page < total_pages ? (current_page + 1): nil
|
110
|
-
end
|
111
|
-
|
112
|
-
def offset
|
113
|
-
(current_page - 1) * @per_page
|
114
|
-
end
|
115
|
-
|
116
|
-
def method_missing(method, *args, &block)
|
117
|
-
super unless method.to_s[/^each_with_.*/]
|
118
|
-
|
119
|
-
each_with_attribute method.to_s.gsub(/^each_with_/, ''), &block
|
120
|
-
end
|
121
|
-
|
122
|
-
def each_with_groupby_and_count(&block)
|
123
|
-
results[:matches].each_with_index do |match, index|
|
124
|
-
yield self[index], match[:attributes]["@groupby"], match[:attributes]["@count"]
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def each_with_attribute(attribute, &block)
|
129
|
-
results[:matches].each_with_index do |match, index|
|
130
|
-
yield self[index], (match[:attributes][attribute] || match[:attributes]["@#{attribute}"])
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def each_with_weighting(&block)
|
135
|
-
results[:matches].each_with_index do |match, index|
|
136
|
-
yield self[index], match[:weight]
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def inject_with_groupby_and_count(initial = nil, &block)
|
141
|
-
index = -1
|
142
|
-
results[:matches].inject(initial) do |memo, match|
|
143
|
-
index += 1
|
144
|
-
yield memo, self[index], match[:attributes]["@groupby"], match[:attributes]["@count"]
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
module ThinkingSphinx
|
2
|
-
class FacetCollection < Hash
|
3
|
-
attr_accessor :arguments
|
4
|
-
|
5
|
-
def initialize(arguments)
|
6
|
-
@arguments = arguments.clone
|
7
|
-
@facet_names = []
|
8
|
-
end
|
9
|
-
|
10
|
-
def add_from_results(facet, results)
|
11
|
-
name = ThinkingSphinx::Facet.name_for(facet)
|
12
|
-
|
13
|
-
self[name] ||= {}
|
14
|
-
@facet_names << name
|
15
|
-
|
16
|
-
return if results.empty?
|
17
|
-
|
18
|
-
facet = facet_from_object(results.first, facet) if facet.is_a?(String)
|
19
|
-
|
20
|
-
results.each_with_groupby_and_count { |result, group, count|
|
21
|
-
facet_value = facet.value(result, group)
|
22
|
-
|
23
|
-
self[name][facet_value] ||= 0
|
24
|
-
self[name][facet_value] += count
|
25
|
-
}
|
26
|
-
end
|
27
|
-
|
28
|
-
def for(hash = {})
|
29
|
-
arguments = @arguments.clone
|
30
|
-
options = arguments.extract_options!
|
31
|
-
options[:with] ||= {}
|
32
|
-
|
33
|
-
hash.each do |key, value|
|
34
|
-
attrib = ThinkingSphinx::Facet.attribute_name_from_value(key, value)
|
35
|
-
options[:with][attrib] = underlying_value key, value
|
36
|
-
end
|
37
|
-
|
38
|
-
arguments << options
|
39
|
-
ThinkingSphinx::Search.search *arguments
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def underlying_value(key, value)
|
45
|
-
case value
|
46
|
-
when Array
|
47
|
-
value.collect { |item| underlying_value(key, item) }
|
48
|
-
when String
|
49
|
-
value.to_crc32
|
50
|
-
else
|
51
|
-
value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def facet_from_object(object, name)
|
56
|
-
object.sphinx_facets.detect { |facet| facet.attribute_name == name }
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
module ThinkingSphinx
|
2
|
-
class Search
|
3
|
-
module Facets
|
4
|
-
# Model.facets *args
|
5
|
-
# ThinkingSphinx::Search.facets *args
|
6
|
-
# ThinkingSphinx::Search.facets *args, :all_attributes => true
|
7
|
-
# ThinkingSphinx::Search.facets *args, :class_facet => false
|
8
|
-
#
|
9
|
-
def facets(*args)
|
10
|
-
options = args.extract_options!
|
11
|
-
|
12
|
-
if options[:class]
|
13
|
-
facets_for_model options[:class], args, options
|
14
|
-
else
|
15
|
-
facets_for_all_models args, options
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def facets_for_model(klass, args, options)
|
22
|
-
hash = ThinkingSphinx::FacetCollection.new args + [options]
|
23
|
-
options = options.clone.merge! facet_query_options
|
24
|
-
|
25
|
-
klass.sphinx_facets.inject(hash) do |hash, facet|
|
26
|
-
unless facet.name == :class && !options[:class_facet]
|
27
|
-
options[:group_by] = facet.attribute_name
|
28
|
-
hash.add_from_results facet, search(*(args + [options]))
|
29
|
-
end
|
30
|
-
|
31
|
-
hash
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def facets_for_all_models(args, options)
|
36
|
-
options = GlobalFacetOptions.merge(options)
|
37
|
-
hash = ThinkingSphinx::FacetCollection.new args + [options]
|
38
|
-
options = options.merge! facet_query_options
|
39
|
-
|
40
|
-
facet_names(options).inject(hash) do |hash, name|
|
41
|
-
options[:group_by] = name
|
42
|
-
hash.add_from_results name, search(*(args + [options]))
|
43
|
-
hash
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def facet_query_options
|
48
|
-
config = ThinkingSphinx::Configuration.instance
|
49
|
-
max = config.configuration.searchd.max_matches || 1000
|
50
|
-
|
51
|
-
{
|
52
|
-
:group_function => :attr,
|
53
|
-
:limit => max,
|
54
|
-
:max_matches => max
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
|
-
def facet_classes(options)
|
59
|
-
options[:classes] || ThinkingSphinx.indexed_models.collect { |model|
|
60
|
-
model.constantize
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
def facet_names(options)
|
65
|
-
classes = facet_classes(options)
|
66
|
-
names = options[:all_attributes] ?
|
67
|
-
facet_names_for_all_classes(classes) :
|
68
|
-
facet_names_common_to_all_classes(classes)
|
69
|
-
|
70
|
-
names.delete "class_crc" unless options[:class_facet]
|
71
|
-
names
|
72
|
-
end
|
73
|
-
|
74
|
-
def facet_names_for_all_classes(classes)
|
75
|
-
all_facets = classes.collect { |klass| klass.sphinx_facets }.flatten
|
76
|
-
|
77
|
-
all_facets.group_by { |facet|
|
78
|
-
facet.name
|
79
|
-
}.collect { |name, facets|
|
80
|
-
if facets.collect { |facet| facet.type }.uniq.length > 1
|
81
|
-
raise "Facet #{name} exists in more than one model with different types"
|
82
|
-
end
|
83
|
-
facets.first.attribute_name
|
84
|
-
}
|
85
|
-
end
|
86
|
-
|
87
|
-
def facet_names_common_to_all_classes(classes)
|
88
|
-
facet_names_for_all_classes(classes).select { |name|
|
89
|
-
classes.all? { |klass|
|
90
|
-
klass.sphinx_facets.detect { |facet|
|
91
|
-
facet.attribute_name == name
|
92
|
-
}
|
93
|
-
}
|
94
|
-
}
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,107 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
|
3
|
-
describe "ThinkingSphinx::ActiveRecord::Search" do
|
4
|
-
it "should add search_for_ids to ActiveRecord::Base" do
|
5
|
-
ActiveRecord::Base.methods.should include("search_for_ids")
|
6
|
-
end
|
7
|
-
|
8
|
-
it "should add search_for_ids to ActiveRecord::Base" do
|
9
|
-
ActiveRecord::Base.methods.should include("search")
|
10
|
-
end
|
11
|
-
|
12
|
-
it "should add search_count to ActiveRecord::Base" do
|
13
|
-
ActiveRecord::Base.methods.should include("search_count")
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should add search_for_id to ActiveRecord::Base" do
|
17
|
-
ActiveRecord::Base.methods.should include("search_for_id")
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "search_for_ids method" do
|
21
|
-
before :each do
|
22
|
-
ThinkingSphinx::Search.stub_method(:search_for_ids => true)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should call ThinkingSphinx::Search#search_for_ids with the class option set" do
|
26
|
-
Person.search_for_ids("search")
|
27
|
-
|
28
|
-
ThinkingSphinx::Search.should have_received(:search_for_ids).with(
|
29
|
-
"search", :class => Person
|
30
|
-
)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should override the class option" do
|
34
|
-
Person.search_for_ids("search", :class => Friendship)
|
35
|
-
|
36
|
-
ThinkingSphinx::Search.should have_received(:search_for_ids).with(
|
37
|
-
"search", :class => Person
|
38
|
-
)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "search method" do
|
43
|
-
before :each do
|
44
|
-
ThinkingSphinx::Search.stub_method(:search => true)
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should call ThinkingSphinx::Search#search with the class option set" do
|
48
|
-
Person.search("search")
|
49
|
-
|
50
|
-
ThinkingSphinx::Search.should have_received(:search).with(
|
51
|
-
"search", :class => Person
|
52
|
-
)
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should override the class option" do
|
56
|
-
Person.search("search", :class => Friendship)
|
57
|
-
|
58
|
-
ThinkingSphinx::Search.should have_received(:search).with(
|
59
|
-
"search", :class => Person
|
60
|
-
)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe "search_for_id method" do
|
65
|
-
before :each do
|
66
|
-
ThinkingSphinx::Search.stub_method(:search_for_id => true)
|
67
|
-
end
|
68
|
-
|
69
|
-
it "should call ThinkingSphinx::Search#search with the class option set" do
|
70
|
-
Person.search_for_id(10)
|
71
|
-
|
72
|
-
ThinkingSphinx::Search.should have_received(:search_for_id).with(
|
73
|
-
10, :class => Person
|
74
|
-
)
|
75
|
-
end
|
76
|
-
|
77
|
-
it "should override the class option" do
|
78
|
-
Person.search_for_id(10, :class => Friendship)
|
79
|
-
|
80
|
-
ThinkingSphinx::Search.should have_received(:search_for_id).with(
|
81
|
-
10, :class => Person
|
82
|
-
)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
describe "search_count method" do
|
87
|
-
before :each do
|
88
|
-
ThinkingSphinx::Search.stub_method(:count => true)
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should call ThinkingSphinx::Search#search with the class option set" do
|
92
|
-
Person.search_count("search")
|
93
|
-
|
94
|
-
ThinkingSphinx::Search.should have_received(:count).with(
|
95
|
-
"search", :class => Person
|
96
|
-
)
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should override the class option" do
|
100
|
-
Person.search_count("search", :class => Friendship)
|
101
|
-
|
102
|
-
ThinkingSphinx::Search.should have_received(:count).with(
|
103
|
-
"search", :class => Person
|
104
|
-
)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
@@ -1,232 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
|
3
|
-
describe ThinkingSphinx::Attribute do
|
4
|
-
before :each do
|
5
|
-
@index = ThinkingSphinx::Index.new(Person)
|
6
|
-
@source = ThinkingSphinx::Source.new(@index)
|
7
|
-
end
|
8
|
-
|
9
|
-
describe '#initialize' do
|
10
|
-
it 'raises if no columns are provided so that configuration errors are easier to track down' do
|
11
|
-
lambda {
|
12
|
-
ThinkingSphinx::Attribute.new(@source, [])
|
13
|
-
}.should raise_error(RuntimeError)
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
|
17
|
-
lambda {
|
18
|
-
ThinkingSphinx::Attribute.new(@source, [1234])
|
19
|
-
}.should raise_error(RuntimeError)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "unique_name method" do
|
24
|
-
before :each do
|
25
|
-
@attribute = ThinkingSphinx::Attribute.new @source, [
|
26
|
-
Object.stub_instance(:__stack => [], :__name => "col_name")
|
27
|
-
]
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should use the alias if there is one" do
|
31
|
-
@attribute.alias = "alias"
|
32
|
-
@attribute.unique_name.should == "alias"
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should use the alias if there's multiple columns" do
|
36
|
-
@attribute.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
|
37
|
-
@attribute.unique_name.should be_nil
|
38
|
-
|
39
|
-
@attribute.alias = "alias"
|
40
|
-
@attribute.unique_name.should == "alias"
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should use the column name if there's no alias and just one column" do
|
44
|
-
@attribute.unique_name.should == "col_name"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "column_with_prefix method" do
|
49
|
-
before :each do
|
50
|
-
@attribute = ThinkingSphinx::Attribute.new @source, [
|
51
|
-
ThinkingSphinx::Index::FauxColumn.new(:col_name)
|
52
|
-
]
|
53
|
-
@attribute.columns.each { |col| @attribute.associations[col] = [] }
|
54
|
-
@attribute.model = Person
|
55
|
-
|
56
|
-
@first_join = Object.stub_instance(:aliased_table_name => "tabular")
|
57
|
-
@second_join = Object.stub_instance(:aliased_table_name => "data")
|
58
|
-
|
59
|
-
@first_assoc = ThinkingSphinx::Association.stub_instance(
|
60
|
-
:join => @first_join, :has_column? => true
|
61
|
-
)
|
62
|
-
@second_assoc = ThinkingSphinx::Association.stub_instance(
|
63
|
-
:join => @second_join, :has_column? => true
|
64
|
-
)
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should return the column name if the column is a string" do
|
68
|
-
@attribute.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
|
69
|
-
@attribute.send(:column_with_prefix, @attribute.columns.first).should == "string"
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should return the column with model's table prefix if there's no associations for the column" do
|
73
|
-
@attribute.send(:column_with_prefix, @attribute.columns.first).should == "`people`.`col_name`"
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should return the column with its join table prefix if an association exists" do
|
77
|
-
column = @attribute.columns.first
|
78
|
-
@attribute.associations[column] = [@first_assoc]
|
79
|
-
@attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
|
80
|
-
end
|
81
|
-
|
82
|
-
it "should return multiple columns concatenated if more than one association exists" do
|
83
|
-
column = @attribute.columns.first
|
84
|
-
@attribute.associations[column] = [@first_assoc, @second_assoc]
|
85
|
-
@attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
describe "is_many? method" do
|
90
|
-
before :each do
|
91
|
-
@assoc_a = Object.stub_instance(:is_many? => true)
|
92
|
-
@assoc_b = Object.stub_instance(:is_many? => true)
|
93
|
-
@assoc_c = Object.stub_instance(:is_many? => true)
|
94
|
-
|
95
|
-
@attribute = ThinkingSphinx::Attribute.new(
|
96
|
-
@source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
|
97
|
-
)
|
98
|
-
@attribute.associations = {
|
99
|
-
:a => @assoc_a, :b => @assoc_b, :c => @assoc_c
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should return true if all associations return true to is_many?" do
|
104
|
-
@attribute.send(:is_many?).should be_true
|
105
|
-
end
|
106
|
-
|
107
|
-
it "should return true if one association returns true to is_many?" do
|
108
|
-
@assoc_b.stub_method(:is_many? => false)
|
109
|
-
@assoc_c.stub_method(:is_many? => false)
|
110
|
-
|
111
|
-
@attribute.send(:is_many?).should be_true
|
112
|
-
end
|
113
|
-
|
114
|
-
it "should return false if all associations return false to is_many?" do
|
115
|
-
@assoc_a.stub_method(:is_many? => false)
|
116
|
-
@assoc_b.stub_method(:is_many? => false)
|
117
|
-
@assoc_c.stub_method(:is_many? => false)
|
118
|
-
|
119
|
-
@attribute.send(:is_many?).should be_false
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
describe "is_string? method" do
|
124
|
-
before :each do
|
125
|
-
@col_a = ThinkingSphinx::Index::FauxColumn.new("a")
|
126
|
-
@col_b = ThinkingSphinx::Index::FauxColumn.new("b")
|
127
|
-
@col_c = ThinkingSphinx::Index::FauxColumn.new("c")
|
128
|
-
|
129
|
-
@attribute = ThinkingSphinx::Attribute.new(
|
130
|
-
@source, [@col_a, @col_b, @col_c]
|
131
|
-
)
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should return true if all columns return true to is_string?" do
|
135
|
-
@attribute.send(:is_string?).should be_true
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should return false if one column returns true to is_string?" do
|
139
|
-
@col_a.send(:instance_variable_set, :@name, :a)
|
140
|
-
@attribute.send(:is_string?).should be_false
|
141
|
-
end
|
142
|
-
|
143
|
-
it "should return false if all columns return false to is_string?" do
|
144
|
-
@col_a.send(:instance_variable_set, :@name, :a)
|
145
|
-
@col_b.send(:instance_variable_set, :@name, :b)
|
146
|
-
@col_c.send(:instance_variable_set, :@name, :c)
|
147
|
-
@attribute.send(:is_string?).should be_false
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe "type method" do
|
152
|
-
before :each do
|
153
|
-
@column = ThinkingSphinx::Index::FauxColumn.new(:col_name)
|
154
|
-
@attribute = ThinkingSphinx::Attribute.new(@source, [@column])
|
155
|
-
@attribute.model = Person
|
156
|
-
@attribute.stub_method(:is_many? => false)
|
157
|
-
end
|
158
|
-
|
159
|
-
it "should return :multi if is_many? is true" do
|
160
|
-
@attribute.stub_method(:is_many? => true)
|
161
|
-
@attribute.send(:type).should == :multi
|
162
|
-
end
|
163
|
-
|
164
|
-
it "should return :string if there's more than one association" do
|
165
|
-
@attribute.associations = {:a => [:assoc], :b => [:assoc]}
|
166
|
-
@attribute.send(:type).should == :string
|
167
|
-
end
|
168
|
-
|
169
|
-
it "should return the column type from the database if not :multi or more than one association" do
|
170
|
-
@column.send(:instance_variable_set, :@name, "birthday")
|
171
|
-
@attribute.send(:type).should == :datetime
|
172
|
-
|
173
|
-
@attribute.send(:instance_variable_set, :@type, nil)
|
174
|
-
@column.send(:instance_variable_set, :@name, "first_name")
|
175
|
-
@attribute.send(:type).should == :string
|
176
|
-
|
177
|
-
@attribute.send(:instance_variable_set, :@type, nil)
|
178
|
-
@column.send(:instance_variable_set, :@name, "id")
|
179
|
-
@attribute.send(:type).should == :integer
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
describe "all_ints? method" do
|
184
|
-
it "should return true if all columns are integers" do
|
185
|
-
attribute = ThinkingSphinx::Attribute.new(@source,
|
186
|
-
[ ThinkingSphinx::Index::FauxColumn.new(:id),
|
187
|
-
ThinkingSphinx::Index::FauxColumn.new(:team_id) ]
|
188
|
-
)
|
189
|
-
attribute.model = Person
|
190
|
-
attribute.columns.each { |col| attribute.associations[col] = [] }
|
191
|
-
|
192
|
-
attribute.send(:all_ints?).should be_true
|
193
|
-
end
|
194
|
-
|
195
|
-
it "should return false if only some columns are integers" do
|
196
|
-
attribute = ThinkingSphinx::Attribute.new(@source,
|
197
|
-
[ ThinkingSphinx::Index::FauxColumn.new(:id),
|
198
|
-
ThinkingSphinx::Index::FauxColumn.new(:first_name) ]
|
199
|
-
)
|
200
|
-
attribute.model = Person
|
201
|
-
attribute.columns.each { |col| attribute.associations[col] = [] }
|
202
|
-
|
203
|
-
attribute.send(:all_ints?).should be_false
|
204
|
-
end
|
205
|
-
|
206
|
-
it "should return false if no columns are integers" do
|
207
|
-
attribute = ThinkingSphinx::Attribute.new(@source,
|
208
|
-
[ ThinkingSphinx::Index::FauxColumn.new(:first_name),
|
209
|
-
ThinkingSphinx::Index::FauxColumn.new(:last_name) ]
|
210
|
-
)
|
211
|
-
attribute.model = Person
|
212
|
-
attribute.columns.each { |col| attribute.associations[col] = [] }
|
213
|
-
|
214
|
-
attribute.send(:all_ints?).should be_false
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
describe "with custom queries" do
|
219
|
-
before :each do
|
220
|
-
index = CricketTeam.sphinx_indexes.first
|
221
|
-
@statement = index.sources.first.to_riddle_for_core(0, 0).sql_attr_multi.last
|
222
|
-
end
|
223
|
-
|
224
|
-
it "should track the query type accordingly" do
|
225
|
-
@statement.should match(/uint tags from query/)
|
226
|
-
end
|
227
|
-
|
228
|
-
it "should include the SQL statement" do
|
229
|
-
@statement.should match(/SELECT cricket_team_id, id FROM tags/)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
|
3
|
-
describe ThinkingSphinx::Collection do
|
4
|
-
it "should behave like WillPaginate::Collection" do
|
5
|
-
ThinkingSphinx::Collection.instance_methods.should include("previous_page")
|
6
|
-
ThinkingSphinx::Collection.instance_methods.should include("next_page")
|
7
|
-
ThinkingSphinx::Collection.instance_methods.should include("current_page")
|
8
|
-
ThinkingSphinx::Collection.instance_methods.should include("total_pages")
|
9
|
-
ThinkingSphinx::Collection.instance_methods.should include("total_entries")
|
10
|
-
ThinkingSphinx::Collection.instance_methods.should include("offset")
|
11
|
-
|
12
|
-
ThinkingSphinx::Collection.ancestors.should include(Array)
|
13
|
-
end
|
14
|
-
end
|