thinking-sphinx 2.0.11 → 2.0.12
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/HISTORY +23 -2
- data/README.textile +5 -0
- data/features/attribute_transformation.feature +4 -4
- data/features/support/env.rb +0 -1
- data/features/thinking_sphinx/db/fixtures/alphas.rb +8 -10
- data/lib/cucumber/thinking_sphinx/internal_world.rb +7 -2
- data/lib/cucumber/thinking_sphinx/sql_logger.rb +16 -4
- data/lib/thinking_sphinx/active_record.rb +5 -1
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +14 -5
- data/lib/thinking_sphinx/attribute.rb +3 -3
- data/lib/thinking_sphinx/auto_version.rb +2 -2
- data/lib/thinking_sphinx/configuration.rb +8 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +1 -1
- data/lib/thinking_sphinx/facet.rb +19 -19
- data/lib/thinking_sphinx/index.rb +3 -1
- data/lib/thinking_sphinx/index/builder.rb +5 -0
- data/lib/thinking_sphinx/property.rb +43 -41
- data/lib/thinking_sphinx/search.rb +23 -4
- data/lib/thinking_sphinx/source.rb +5 -5
- data/lib/thinking_sphinx/source/sql.rb +33 -16
- data/lib/thinking_sphinx/version.rb +1 -1
- data/spec/fixtures/models.rb +3 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/sphinx_helper.rb +7 -1
- data/spec/thinking_sphinx/active_record_spec.rb +15 -0
- data/spec/thinking_sphinx/auto_version_spec.rb +8 -0
- data/spec/thinking_sphinx/index/builder_spec.rb +126 -105
- data/spec/thinking_sphinx/index_spec.rb +6 -0
- data/spec/thinking_sphinx/search_spec.rb +27 -6
- data/spec/thinking_sphinx/source_spec.rb +17 -3
- metadata +63 -64
@@ -95,6 +95,11 @@ module ThinkingSphinx
|
|
95
95
|
populate if @options[:populate]
|
96
96
|
end
|
97
97
|
|
98
|
+
def ==(object)
|
99
|
+
populate
|
100
|
+
super
|
101
|
+
end
|
102
|
+
|
98
103
|
def to_a
|
99
104
|
populate
|
100
105
|
@array
|
@@ -442,6 +447,8 @@ module ThinkingSphinx
|
|
442
447
|
def compose_results
|
443
448
|
if options[:ids_only]
|
444
449
|
compose_ids_results
|
450
|
+
elsif options[:attributes_only]
|
451
|
+
compose_attributes_results
|
445
452
|
elsif options[:only]
|
446
453
|
compose_only_results
|
447
454
|
else
|
@@ -458,6 +465,16 @@ module ThinkingSphinx
|
|
458
465
|
}
|
459
466
|
end
|
460
467
|
|
468
|
+
def compose_attributes_results
|
469
|
+
replace @results[:matches].collect { |match|
|
470
|
+
attributes = {}
|
471
|
+
match[:attributes].each do |name, value|
|
472
|
+
attributes[name.to_sym] = match[:attributes][name]
|
473
|
+
end
|
474
|
+
attributes
|
475
|
+
}
|
476
|
+
end
|
477
|
+
|
461
478
|
def compose_only_results
|
462
479
|
replace @results[:matches].collect { |match|
|
463
480
|
case only = options[:only]
|
@@ -544,7 +561,7 @@ module ThinkingSphinx
|
|
544
561
|
[
|
545
562
|
:max_matches, :group_by, :group_function, :group_clause,
|
546
563
|
:group_distinct, :id_range, :cut_off, :retry_count, :retry_delay,
|
547
|
-
:rank_mode, :max_query_time, :field_weights
|
564
|
+
:rank_mode, :rank_expr, :max_query_time, :field_weights
|
548
565
|
].each do |key|
|
549
566
|
value = options[key] || index_options[key]
|
550
567
|
client.send("#{key}=", value) if value
|
@@ -775,8 +792,10 @@ module ThinkingSphinx
|
|
775
792
|
filter_value(value.first).first..filter_value(value.last).first
|
776
793
|
when Array
|
777
794
|
value.collect { |v| filter_value(v) }.flatten
|
778
|
-
when
|
779
|
-
[value.
|
795
|
+
when Time
|
796
|
+
[value.to_i]
|
797
|
+
when Date
|
798
|
+
[Time.utc(value.year, value.month, value.day).to_i]
|
780
799
|
when NilClass
|
781
800
|
0
|
782
801
|
else
|
@@ -885,7 +904,7 @@ module ThinkingSphinx
|
|
885
904
|
index_options = klass.sphinx_index_options
|
886
905
|
|
887
906
|
ids = matches.collect { |match| match[:attributes]["sphinx_internal_id"] }
|
888
|
-
instances = ids.length > 0 ? klass.find(
|
907
|
+
instances = ids.length > 0 ? klass.unscoped.find(
|
889
908
|
:all,
|
890
909
|
:joins => options[:joins],
|
891
910
|
:conditions => {klass.primary_key_for_sphinx.to_sym => ids},
|
@@ -27,11 +27,6 @@ module ThinkingSphinx
|
|
27
27
|
@model, [], initial_joins
|
28
28
|
)
|
29
29
|
|
30
|
-
unless @model.descends_from_active_record?
|
31
|
-
stored_class = @model.store_full_sti_class ? @model.name : @model.name.demodulize
|
32
|
-
@conditions << "#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)} = '#{stored_class}'"
|
33
|
-
end
|
34
|
-
|
35
30
|
add_internal_attributes_and_facets
|
36
31
|
end
|
37
32
|
|
@@ -97,6 +92,11 @@ module ThinkingSphinx
|
|
97
92
|
source.sql_db = config[:database]
|
98
93
|
source.sql_port = config[:port]
|
99
94
|
source.sql_sock = config[:socket]
|
95
|
+
|
96
|
+
# MySQL SSL support
|
97
|
+
source.mysql_ssl_ca = config[:sslca] if config[:sslca]
|
98
|
+
source.mysql_ssl_cert = config[:sslcert] if config[:sslcert]
|
99
|
+
source.mysql_ssl_key = config[:sslkey] if config[:sslkey]
|
100
100
|
end
|
101
101
|
|
102
102
|
def set_source_fields(source)
|
@@ -6,9 +6,9 @@ module ThinkingSphinx
|
|
6
6
|
# the version filtered for delta values, send through :delta => true in
|
7
7
|
# the options. Won't do much though if the index isn't set up to support a
|
8
8
|
# delta sibling.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# Examples:
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# source.to_sql
|
13
13
|
# source.to_sql(:delta => true)
|
14
14
|
#
|
@@ -32,10 +32,10 @@ module ThinkingSphinx
|
|
32
32
|
# Simple helper method for the query range SQL - which is a statement that
|
33
33
|
# returns minimum and maximum id values. These can be filtered by delta -
|
34
34
|
# so pass in :delta => true to get the delta version of the SQL.
|
35
|
-
#
|
35
|
+
#
|
36
36
|
def to_sql_query_range(options={})
|
37
37
|
return nil if @index.options[:disable_range]
|
38
|
-
|
38
|
+
|
39
39
|
min_statement = adapter.convert_nulls(
|
40
40
|
"MIN(#{quote_column(@model.primary_key_for_sphinx)})", 1
|
41
41
|
)
|
@@ -54,7 +54,7 @@ module ThinkingSphinx
|
|
54
54
|
|
55
55
|
# Simple helper method for the query info SQL - which is a statement that
|
56
56
|
# returns the single row for a corresponding id.
|
57
|
-
#
|
57
|
+
#
|
58
58
|
def to_sql_query_info(offset)
|
59
59
|
"SELECT * FROM #{@model.quoted_table_name} WHERE " +
|
60
60
|
"#{quote_column(@model.primary_key_for_sphinx)} = (($id - #{offset}) / #{ThinkingSphinx.context.indexed_models.size})"
|
@@ -64,7 +64,7 @@ module ThinkingSphinx
|
|
64
64
|
unique_id_expr = ThinkingSphinx.unique_id_expression(adapter, offset)
|
65
65
|
|
66
66
|
(
|
67
|
-
["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} #{unique_id_expr} AS #{quote_column(@model.primary_key_for_sphinx)} "] +
|
67
|
+
["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} #{unique_id_expr} AS #{quote_column(@model.primary_key_for_sphinx)} "] +
|
68
68
|
@fields.collect { |field| field.to_select_sql } +
|
69
69
|
@attributes.collect { |attribute| attribute.to_select_sql }
|
70
70
|
).compact.join(", ")
|
@@ -92,7 +92,7 @@ module ThinkingSphinx
|
|
92
92
|
end
|
93
93
|
|
94
94
|
(
|
95
|
-
["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)}"] +
|
95
|
+
["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)}"] +
|
96
96
|
@fields.collect { |field| field.to_group_sql }.compact +
|
97
97
|
@attributes.collect { |attribute| attribute.to_group_sql }.compact +
|
98
98
|
@groupings + internal_groupings
|
@@ -118,40 +118,57 @@ module ThinkingSphinx
|
|
118
118
|
def crc_column
|
119
119
|
if @model.table_exists? &&
|
120
120
|
@model.column_names.include?(@model.inheritance_column)
|
121
|
-
|
121
|
+
|
122
122
|
types = types_to_crcs
|
123
123
|
return @model.to_crc32.to_s if types.empty?
|
124
|
-
|
124
|
+
|
125
125
|
adapter.case(adapter.convert_nulls(
|
126
|
-
adapter.quote_with_table(@model.inheritance_column)),
|
126
|
+
adapter.quote_with_table(@model.inheritance_column), @model.name),
|
127
127
|
types, @model.to_crc32)
|
128
128
|
else
|
129
129
|
@model.to_crc32.to_s
|
130
130
|
end
|
131
131
|
end
|
132
|
-
|
132
|
+
|
133
133
|
def internal_class_column
|
134
|
+
quoted_name = "'#{@model.name}'"
|
135
|
+
|
134
136
|
if @model.table_exists? &&
|
135
137
|
@model.column_names.include?(@model.inheritance_column)
|
136
|
-
|
138
|
+
|
139
|
+
types = types_to_hash
|
140
|
+
return quoted_name if types.empty?
|
141
|
+
|
142
|
+
adapter.case(adapter.convert_nulls(
|
143
|
+
adapter.quote_with_table(@model.inheritance_column), @model.name),
|
144
|
+
types, quoted_name)
|
137
145
|
else
|
138
|
-
|
146
|
+
quoted_name
|
139
147
|
end
|
140
148
|
end
|
141
|
-
|
149
|
+
|
142
150
|
def type_values
|
151
|
+
return @model.sphinx_types unless @model.sphinx_types.nil?
|
152
|
+
|
143
153
|
@model.connection.select_values <<-SQL
|
144
154
|
SELECT DISTINCT #{@model.inheritance_column}
|
145
155
|
FROM #{@model.table_name}
|
146
156
|
SQL
|
147
157
|
end
|
148
|
-
|
158
|
+
|
149
159
|
def types_to_crcs
|
150
160
|
type_values.compact.inject({}) { |hash, type|
|
151
161
|
hash[type] = type.to_crc32
|
152
162
|
hash
|
153
163
|
}
|
154
164
|
end
|
165
|
+
|
166
|
+
def types_to_hash
|
167
|
+
type_values.compact.inject({}) { |hash, type|
|
168
|
+
hash[type] = "'#{type}'"
|
169
|
+
hash
|
170
|
+
}
|
171
|
+
end
|
155
172
|
end
|
156
173
|
end
|
157
|
-
end
|
174
|
+
end
|
data/spec/fixtures/models.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -10,7 +10,6 @@ require 'bundler'
|
|
10
10
|
Bundler.require :default, :development
|
11
11
|
|
12
12
|
require 'active_support/core_ext/module/attribute_accessors'
|
13
|
-
require 'active_support/core_ext/class/inheritable_attributes'
|
14
13
|
require "#{File.dirname(__FILE__)}/sphinx_helper"
|
15
14
|
|
16
15
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
data/spec/sphinx_helper.rb
CHANGED
@@ -18,6 +18,9 @@ class SphinxHelper
|
|
18
18
|
@username = config['username']
|
19
19
|
@password = config['password']
|
20
20
|
@socket = config['socket']
|
21
|
+
@sslca = config['sslca']
|
22
|
+
@sslcert = config['sslcert']
|
23
|
+
@sslkey = config['sslkey']
|
21
24
|
end
|
22
25
|
|
23
26
|
@path = File.expand_path(File.dirname(__FILE__))
|
@@ -30,7 +33,10 @@ class SphinxHelper
|
|
30
33
|
:username => @username,
|
31
34
|
:password => @password,
|
32
35
|
:host => @host,
|
33
|
-
:socket => @socket
|
36
|
+
:socket => @socket,
|
37
|
+
:sslca => @sslca,
|
38
|
+
:sslcert => @sslcert,
|
39
|
+
:sslkey => @sslkey
|
34
40
|
)
|
35
41
|
ActiveRecord::Base.logger = Logger.new(File.open('tmp/activerecord.log', 'a'))
|
36
42
|
|
@@ -419,6 +419,21 @@ describe ThinkingSphinx::ActiveRecord do
|
|
419
419
|
end
|
420
420
|
end
|
421
421
|
|
422
|
+
describe '#types_for_sphinx' do
|
423
|
+
after :each do
|
424
|
+
Person.set_sphinx_types nil
|
425
|
+
end
|
426
|
+
|
427
|
+
it "should return nil by default" do
|
428
|
+
Person.sphinx_types.should == nil
|
429
|
+
end
|
430
|
+
|
431
|
+
it "should return the specified value" do
|
432
|
+
Person.set_sphinx_types %w(Person Parent)
|
433
|
+
Person.sphinx_types.should == %w(Person Parent)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
422
437
|
describe '.sphinx_index_names' do
|
423
438
|
it "should return the core index" do
|
424
439
|
Alpha.define_index { indexes :name }
|
@@ -54,6 +54,14 @@ describe ThinkingSphinx::AutoVersion do
|
|
54
54
|
ThinkingSphinx::AutoVersion.detect
|
55
55
|
end
|
56
56
|
|
57
|
+
it "should require 2.1.0 if using Sphinx 2.0.3" do
|
58
|
+
ThinkingSphinx::AutoVersion.should_receive(:require).
|
59
|
+
with('riddle/2.1.0')
|
60
|
+
|
61
|
+
@config.stub!(:version => '2.0.3-release')
|
62
|
+
ThinkingSphinx::AutoVersion.detect
|
63
|
+
end
|
64
|
+
|
57
65
|
it "should require 2.1.0 if using Sphinx 2.1.0 dev" do
|
58
66
|
ThinkingSphinx::AutoVersion.should_receive(:require).
|
59
67
|
with('riddle/2.1.0')
|
@@ -10,338 +10,338 @@ describe ThinkingSphinx::Index::Builder do
|
|
10
10
|
indexes first_name, last_name
|
11
11
|
has birthday
|
12
12
|
has id, :as => :internal_id
|
13
|
-
|
13
|
+
|
14
14
|
set_property :sql_range_step => 1000
|
15
|
-
|
15
|
+
|
16
16
|
where "birthday <= NOW()"
|
17
17
|
group_by "first_name"
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
@source = @index.sources.first
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it "should return an index" do
|
24
24
|
@index.should be_a_kind_of(ThinkingSphinx::Index)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it "should have one source for the index" do
|
28
28
|
@index.sources.length.should == 1
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
it "should have two fields" do
|
32
32
|
@source.fields.length.should == 2
|
33
33
|
@source.fields[0].unique_name.should == :first_name
|
34
34
|
@source.fields[1].unique_name.should == :last_name
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
it "should have two attributes alongside the internal ones" do
|
38
38
|
@source.attributes.length.should == 2 + internal_attribute_count
|
39
39
|
@source.attributes[internal_attribute_count].unique_name.should == :birthday
|
40
40
|
@source.attributes[1 + internal_attribute_count].unique_name.should == :internal_id
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
it "should have one condition" do
|
44
44
|
@source.conditions.length.should == 1
|
45
45
|
@source.conditions.first.should == "birthday <= NOW()"
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
it "should have one grouping" do
|
49
49
|
@source.groupings.length.should == 1
|
50
50
|
@source.groupings.first.should == "first_name"
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
it "should have one option" do
|
54
54
|
@source.options.length.should == 1
|
55
55
|
@source.options[:sql_range_step].should == 1000
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
describe 'aliased field' do
|
60
60
|
before :each do
|
61
61
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
62
62
|
indexes first_name, :as => 'name'
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
@source = @index.sources.first
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
it "should store the alias as a symbol for consistency" do
|
69
69
|
@source.fields.last.unique_name.should == :name
|
70
70
|
end
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
describe 'aliased attribute' do
|
74
74
|
before :each do
|
75
75
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
76
76
|
indexes first_name
|
77
77
|
has :id, :as => 'real_id'
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
@source = @index.sources.first
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
it "should store the alias as a symbol for consistency" do
|
84
84
|
@source.attributes.last.unique_name.should == :real_id
|
85
85
|
end
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
describe "sortable field" do
|
89
89
|
before :each do
|
90
90
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
91
91
|
indexes first_name, :sortable => true
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
@source = @index.sources.first
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
it "should have one field" do
|
98
98
|
@source.fields.length.should == 1
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
it "should have one attribute alongside the internal ones" do
|
102
102
|
@source.attributes.length.should == 1 + internal_attribute_count
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
it "should set the attribute name to have the _sort suffix" do
|
106
106
|
@source.attributes.last.unique_name.should == :first_name_sort
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
it "should set the attribute column to be the same as the field" do
|
110
110
|
@source.attributes.last.columns.length.should == 1
|
111
111
|
@source.attributes.last.columns.first.__name.should == :first_name
|
112
112
|
end
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
describe '#join' do
|
116
116
|
before :each do
|
117
117
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
118
118
|
indexes first_name
|
119
|
-
|
119
|
+
|
120
120
|
join contacts
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
@source = @index.sources.first
|
124
124
|
end
|
125
|
-
|
125
|
+
|
126
126
|
it "should include the explicit join" do
|
127
127
|
@source.joins.length.should == 1
|
128
128
|
end
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
describe "faceted field" do
|
132
132
|
before :each do
|
133
133
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
134
134
|
indexes first_name, :facet => true
|
135
135
|
end
|
136
|
-
|
136
|
+
|
137
137
|
@source = @index.sources.first
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
after :each do
|
141
141
|
Person.sphinx_facets.delete_at(-1)
|
142
142
|
end
|
143
|
-
|
143
|
+
|
144
144
|
it "should have one field" do
|
145
145
|
@source.fields.length.should == 1
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
it "should have one attribute alongside the internal ones" do
|
149
149
|
@source.attributes.length.should == 1 + internal_attribute_count
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
it "should set the attribute name to have the _facet suffix" do
|
153
153
|
@source.attributes.last.unique_name.should == :first_name_facet
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
it "should set the attribute type to integer" do
|
157
157
|
@source.attributes.last.type.should == :integer
|
158
158
|
end
|
159
|
-
|
159
|
+
|
160
160
|
it "should set the attribute column to be the same as the field" do
|
161
161
|
@source.attributes.last.columns.length.should == 1
|
162
162
|
@source.attributes.last.columns.first.__name.should == :first_name
|
163
163
|
end
|
164
164
|
end
|
165
|
-
|
165
|
+
|
166
166
|
describe "faceted integer attribute" do
|
167
167
|
before :each do
|
168
168
|
@index = ThinkingSphinx::Index::Builder.generate(Alpha) do
|
169
169
|
indexes :name
|
170
170
|
has value, :facet => true
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
@source = @index.sources.first
|
174
174
|
end
|
175
|
-
|
175
|
+
|
176
176
|
after :each do
|
177
177
|
Alpha.sphinx_facets.delete_at(-1)
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
it "should have just one attribute alongside the internal ones" do
|
181
181
|
@source.attributes.length.should == 1 + internal_attribute_count
|
182
182
|
end
|
183
183
|
end
|
184
|
-
|
184
|
+
|
185
185
|
describe "faceted timestamp attribute" do
|
186
186
|
before :each do
|
187
187
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
188
188
|
indexes first_name
|
189
189
|
has birthday, :facet => true
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
@source = @index.sources.first
|
193
193
|
end
|
194
|
-
|
194
|
+
|
195
195
|
after :each do
|
196
196
|
Person.sphinx_facets.delete_at(-1)
|
197
197
|
end
|
198
|
-
|
198
|
+
|
199
199
|
it "should have just one attribute alongside the internal ones" do
|
200
200
|
@source.attributes.length.should == 1 + internal_attribute_count
|
201
201
|
end
|
202
202
|
end
|
203
|
-
|
203
|
+
|
204
204
|
describe "faceted boolean attribute" do
|
205
205
|
before :each do
|
206
206
|
@index = ThinkingSphinx::Index::Builder.generate(Beta) do
|
207
207
|
indexes :name
|
208
208
|
has delta, :facet => true
|
209
209
|
end
|
210
|
-
|
210
|
+
|
211
211
|
@source = @index.sources.first
|
212
212
|
end
|
213
|
-
|
213
|
+
|
214
214
|
after :each do
|
215
215
|
Beta.sphinx_facets.delete_at(-1)
|
216
216
|
end
|
217
|
-
|
217
|
+
|
218
218
|
it "should have just one attribute alongside the internal ones" do
|
219
219
|
@source.attributes.length.should == 1 + internal_attribute_count
|
220
220
|
end
|
221
221
|
end
|
222
|
-
|
222
|
+
|
223
223
|
describe "faceted float attribute" do
|
224
224
|
before :each do
|
225
225
|
@index = ThinkingSphinx::Index::Builder.generate(Alpha) do
|
226
226
|
indexes :name
|
227
227
|
has cost, :facet => true
|
228
228
|
end
|
229
|
-
|
229
|
+
|
230
230
|
@source = @index.sources.first
|
231
231
|
end
|
232
|
-
|
232
|
+
|
233
233
|
after :each do
|
234
234
|
Alpha.sphinx_facets.delete_at(-1)
|
235
235
|
end
|
236
|
-
|
236
|
+
|
237
237
|
it "should have just one attribute alongside the internal ones" do
|
238
238
|
@source.attributes.length.should == 1 + internal_attribute_count
|
239
239
|
end
|
240
240
|
end
|
241
|
-
|
241
|
+
|
242
242
|
describe "faceted string attribute" do
|
243
243
|
before :each do
|
244
244
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
245
245
|
indexes first_name
|
246
246
|
has last_name, :facet => true
|
247
247
|
end
|
248
|
-
|
248
|
+
|
249
249
|
@source = @index.sources.first
|
250
250
|
end
|
251
|
-
|
251
|
+
|
252
252
|
after :each do
|
253
253
|
Person.sphinx_facets.delete_at(-1)
|
254
254
|
end
|
255
|
-
|
255
|
+
|
256
256
|
it "should have two attributes alongside the internal ones" do
|
257
257
|
@source.attributes.length.should == 2 + internal_attribute_count
|
258
258
|
end
|
259
|
-
|
259
|
+
|
260
260
|
it "should set the facet attribute name to have the _facet suffix" do
|
261
261
|
@source.attributes.last.unique_name.should == :last_name_facet
|
262
262
|
end
|
263
|
-
|
263
|
+
|
264
264
|
it "should set the attribute type to integer" do
|
265
265
|
@source.attributes.last.type.should == :integer
|
266
266
|
end
|
267
|
-
|
267
|
+
|
268
268
|
it "should set the attribute column to be the same as the field" do
|
269
269
|
@source.attributes.last.columns.length.should == 1
|
270
270
|
@source.attributes.last.columns.first.__name.should == :last_name
|
271
271
|
end
|
272
272
|
end
|
273
|
-
|
273
|
+
|
274
274
|
describe 'faceted manual MVA' do
|
275
275
|
before :each do
|
276
276
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
277
277
|
indexes first_name
|
278
278
|
has 'SQL STATEMENT', :type => :multi, :as => :sql, :facet => true
|
279
279
|
end
|
280
|
-
|
280
|
+
|
281
281
|
@source = @index.sources.first
|
282
282
|
end
|
283
|
-
|
283
|
+
|
284
284
|
after :each do
|
285
285
|
Person.sphinx_facets.delete_at(-1)
|
286
286
|
end
|
287
|
-
|
287
|
+
|
288
288
|
it "should have two attributes alongside the internal ones" do
|
289
289
|
@source.attributes.length.should == 2 + internal_attribute_count
|
290
290
|
end
|
291
|
-
|
291
|
+
|
292
292
|
it "should set the facet attribute name to have the _facet suffix" do
|
293
293
|
@source.attributes.last.unique_name.should == :sql_facet
|
294
294
|
end
|
295
|
-
|
295
|
+
|
296
296
|
it "should keep the original attribute's name set as requested" do
|
297
297
|
@source.attributes[-2].unique_name.should == :sql
|
298
298
|
end
|
299
|
-
|
299
|
+
|
300
300
|
it "should set the attribute type to multi" do
|
301
301
|
@source.attributes.last.type.should == :multi
|
302
302
|
end
|
303
|
-
|
303
|
+
|
304
304
|
it "should set the attribute column to be the same as the field" do
|
305
305
|
@source.attributes.last.columns.length.should == 1
|
306
306
|
@source.attributes.last.columns.first.__name.should == 'SQL STATEMENT'
|
307
307
|
end
|
308
308
|
end
|
309
|
-
|
309
|
+
|
310
310
|
describe 'faceted MVA field' do
|
311
311
|
before :each do
|
312
312
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
313
313
|
indexes tags(:name), :as => :tags, :facet => true
|
314
314
|
end
|
315
|
-
|
315
|
+
|
316
316
|
@source = @index.sources.first
|
317
317
|
end
|
318
|
-
|
318
|
+
|
319
319
|
after :each do
|
320
320
|
Person.sphinx_facets.delete_at(-1)
|
321
321
|
end
|
322
|
-
|
322
|
+
|
323
323
|
it "should have one field" do
|
324
324
|
@source.fields.length.should == 1
|
325
325
|
end
|
326
|
-
|
326
|
+
|
327
327
|
it "should have one attribute alongside the internal ones" do
|
328
328
|
@source.attributes.length.should == 1 + internal_attribute_count
|
329
329
|
end
|
330
|
-
|
330
|
+
|
331
331
|
it "should set the attribute name to have the _facet suffix" do
|
332
332
|
@source.attributes.last.unique_name.should == :tags_facet
|
333
333
|
end
|
334
|
-
|
334
|
+
|
335
335
|
it "should set the attribute type to multi" do
|
336
336
|
@source.attributes.last.type.should == :multi
|
337
337
|
end
|
338
|
-
|
338
|
+
|
339
339
|
it "should set the attribute column to be the same as the field" do
|
340
340
|
@source.attributes.last.columns.length.should == 1
|
341
341
|
@source.attributes.last.columns.first.__name.should == :name
|
342
342
|
end
|
343
343
|
end
|
344
|
-
|
344
|
+
|
345
345
|
describe "no fields" do
|
346
346
|
it "should raise an exception" do
|
347
347
|
lambda {
|
@@ -351,7 +351,7 @@ describe ThinkingSphinx::Index::Builder do
|
|
351
351
|
}.should raise_error
|
352
352
|
end
|
353
353
|
end
|
354
|
-
|
354
|
+
|
355
355
|
describe "explicit source" do
|
356
356
|
before :each do
|
357
357
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
@@ -359,38 +359,38 @@ describe ThinkingSphinx::Index::Builder do
|
|
359
359
|
indexes first_name, last_name
|
360
360
|
has birthday
|
361
361
|
has id, :as => :internal_id
|
362
|
-
|
362
|
+
|
363
363
|
set_property :delta => true
|
364
|
-
|
364
|
+
|
365
365
|
where "birthday <= NOW()"
|
366
366
|
group_by "first_name"
|
367
367
|
end
|
368
368
|
end
|
369
|
-
|
369
|
+
|
370
370
|
@source = @index.sources.first
|
371
371
|
end
|
372
|
-
|
372
|
+
|
373
373
|
it "should return an index" do
|
374
374
|
@index.should be_a_kind_of(ThinkingSphinx::Index)
|
375
375
|
end
|
376
|
-
|
376
|
+
|
377
377
|
it "should have one source for the index" do
|
378
378
|
@index.sources.length.should == 1
|
379
379
|
end
|
380
|
-
|
380
|
+
|
381
381
|
it "should have two fields" do
|
382
382
|
@source.fields.length.should == 2
|
383
383
|
@source.fields[0].unique_name.should == :first_name
|
384
384
|
@source.fields[1].unique_name.should == :last_name
|
385
385
|
end
|
386
|
-
|
386
|
+
|
387
387
|
it "should have two attributes alongside the internal ones" do
|
388
388
|
@source.attributes.length.should == 2 + internal_attribute_count
|
389
389
|
@source.attributes[internal_attribute_count].unique_name.should == :birthday
|
390
390
|
@source.attributes[1 + internal_attribute_count].unique_name.should == :internal_id
|
391
391
|
end
|
392
392
|
end
|
393
|
-
|
393
|
+
|
394
394
|
describe "multiple sources" do
|
395
395
|
before :each do
|
396
396
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
@@ -398,104 +398,125 @@ describe ThinkingSphinx::Index::Builder do
|
|
398
398
|
indexes first_name
|
399
399
|
has birthday
|
400
400
|
end
|
401
|
-
|
401
|
+
|
402
402
|
define_source do
|
403
403
|
indexes last_name
|
404
404
|
has :id, :as => :internal_id
|
405
405
|
end
|
406
406
|
end
|
407
407
|
end
|
408
|
-
|
408
|
+
|
409
409
|
it "should have two sources" do
|
410
410
|
@index.sources.length.should == 2
|
411
411
|
end
|
412
|
-
|
412
|
+
|
413
413
|
it "should have two fields" do
|
414
414
|
@index.fields.length.should == 2
|
415
415
|
end
|
416
|
-
|
416
|
+
|
417
417
|
it "should have one field in each source" do
|
418
418
|
@index.sources.each do |source|
|
419
419
|
source.fields.length.should == 1
|
420
420
|
end
|
421
421
|
end
|
422
|
-
|
422
|
+
|
423
423
|
it "should have two attributes alongside the six internal ones" do
|
424
424
|
@index.attributes.length.should == 2 + (internal_attribute_count * 2)
|
425
425
|
end
|
426
|
-
|
426
|
+
|
427
427
|
it "should have one attribute in each source alongside the internal ones" do
|
428
428
|
@index.sources.each do |source|
|
429
429
|
source.attributes.length.should == 1 + internal_attribute_count
|
430
430
|
end
|
431
431
|
end
|
432
432
|
end
|
433
|
-
|
433
|
+
|
434
|
+
describe "multiple local indexes" do
|
435
|
+
before :each do
|
436
|
+
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
437
|
+
indexes first_name
|
438
|
+
|
439
|
+
use_local_index :other_local_index_1
|
440
|
+
use_local_indices "other_local_index_2", "other_local_index_3"
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
it "should have three additional indexes" do
|
445
|
+
@index.additional_indices.length.should == 3
|
446
|
+
end
|
447
|
+
|
448
|
+
it "should append _core to the name of each local index" do
|
449
|
+
@index.additional_indices[0].should eql("other_local_index_1_core")
|
450
|
+
@index.additional_indices[1].should eql("other_local_index_2_core")
|
451
|
+
@index.additional_indices[2].should eql("other_local_index_3_core")
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
434
455
|
describe "index options" do
|
435
456
|
before :each do
|
436
457
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
437
458
|
indexes first_name
|
438
|
-
|
459
|
+
|
439
460
|
set_property :charset_type => "utf16"
|
440
461
|
set_property :group_concat_max_len => 1024
|
441
462
|
end
|
442
463
|
end
|
443
|
-
|
464
|
+
|
444
465
|
it "should store the index setting for the index" do
|
445
466
|
@index.local_options[:charset_type].should == "utf16"
|
446
467
|
end
|
447
|
-
|
468
|
+
|
448
469
|
it "should store non-Sphinx settings for the index" do
|
449
470
|
@index.local_options[:group_concat_max_len].should == 1024
|
450
471
|
end
|
451
472
|
end
|
452
|
-
|
473
|
+
|
453
474
|
describe "delta options" do
|
454
475
|
before :each do
|
455
476
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
456
477
|
indexes first_name
|
457
|
-
|
478
|
+
|
458
479
|
set_property :delta => true
|
459
480
|
end
|
460
481
|
end
|
461
|
-
|
482
|
+
|
462
483
|
it "should not keep the delta setting in source options" do
|
463
484
|
@index.sources.first.options.should be_empty
|
464
485
|
end
|
465
|
-
|
486
|
+
|
466
487
|
it "should not keep the delta setting in index options" do
|
467
488
|
@index.local_options.should be_empty
|
468
489
|
end
|
469
|
-
|
490
|
+
|
470
491
|
it "should set the index delta object set" do
|
471
492
|
@index.delta_object.should be_a_kind_of(ThinkingSphinx::Deltas::DefaultDelta)
|
472
493
|
end
|
473
494
|
end
|
474
|
-
|
495
|
+
|
475
496
|
context 'index options' do
|
476
497
|
before :each do
|
477
498
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
478
499
|
indexes first_name
|
479
|
-
|
500
|
+
|
480
501
|
set_property :index_exact_words => true
|
481
502
|
end
|
482
503
|
end
|
483
|
-
|
504
|
+
|
484
505
|
it "should track the index_exact_words option to the index" do
|
485
506
|
@index.local_options[:index_exact_words].should be_true
|
486
507
|
end
|
487
508
|
end
|
488
|
-
|
509
|
+
|
489
510
|
context 'with an explicit name' do
|
490
511
|
it "should set the index's name using the provided value" do
|
491
512
|
index = ThinkingSphinx::Index::Builder.generate(Person, 'custom') do
|
492
513
|
indexes first_name
|
493
514
|
end
|
494
|
-
|
515
|
+
|
495
516
|
index.name.should == 'custom'
|
496
517
|
end
|
497
518
|
end
|
498
|
-
|
519
|
+
|
499
520
|
describe "sanitize_sql" do
|
500
521
|
def index
|
501
522
|
@index ||= ThinkingSphinx::Index::Builder.generate(Person) do
|
@@ -503,7 +524,7 @@ describe ThinkingSphinx::Index::Builder do
|
|
503
524
|
where sanitize_sql(["gender = ?", "female"])
|
504
525
|
end
|
505
526
|
end
|
506
|
-
|
527
|
+
|
507
528
|
it "should be aliased to ActiveRecord::Base.sanitize_sql" do
|
508
529
|
index.sources.first.conditions.first.should == index.model.send(:sanitize_sql, ["gender = ?", "female"])
|
509
530
|
end
|