thinking-sphinx 3.2.0 → 3.3.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 +4 -4
- data/.travis.yml +6 -2
- data/Appraisals +13 -0
- data/Gemfile +2 -1
- data/HISTORY +19 -0
- data/README.textile +3 -2
- data/gemfiles/rails_3_2.gemfile +2 -1
- data/gemfiles/rails_4_0.gemfile +2 -1
- data/gemfiles/rails_4_1.gemfile +2 -1
- data/gemfiles/rails_4_2.gemfile +2 -1
- data/gemfiles/rails_5_0.gemfile +12 -0
- data/lib/thinking_sphinx.rb +2 -0
- data/lib/thinking_sphinx/active_record/attribute/type.rb +17 -3
- data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +12 -4
- data/lib/thinking_sphinx/active_record/database_adapters.rb +1 -1
- data/lib/thinking_sphinx/active_record/sql_builder/query.rb +4 -0
- data/lib/thinking_sphinx/active_record/sql_source.rb +1 -1
- data/lib/thinking_sphinx/configuration.rb +3 -2
- data/lib/thinking_sphinx/connection.rb +23 -10
- data/lib/thinking_sphinx/deltas/index_job.rb +6 -2
- data/lib/thinking_sphinx/errors.rb +25 -0
- data/lib/thinking_sphinx/middlewares/active_record_translator.rb +14 -2
- data/lib/thinking_sphinx/railtie.rb +1 -1
- data/lib/thinking_sphinx/rake_interface.rb +71 -23
- data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +15 -7
- data/lib/thinking_sphinx/real_time/populator.rb +3 -3
- data/lib/thinking_sphinx/tasks.rb +7 -8
- data/lib/thinking_sphinx/wildcard.rb +1 -1
- data/spec/acceptance/association_scoping_spec.rb +5 -5
- data/spec/acceptance/attribute_access_spec.rb +4 -4
- data/spec/acceptance/attribute_updates_spec.rb +3 -3
- data/spec/acceptance/batch_searching_spec.rb +4 -4
- data/spec/acceptance/big_integers_spec.rb +6 -6
- data/spec/acceptance/connection_spec.rb +23 -0
- data/spec/acceptance/excerpts_spec.rb +8 -8
- data/spec/acceptance/facets_spec.rb +13 -13
- data/spec/acceptance/geosearching_spec.rb +8 -8
- data/spec/acceptance/grouping_by_attributes_spec.rb +10 -10
- data/spec/acceptance/index_options_spec.rb +16 -16
- data/spec/acceptance/indexing_spec.rb +3 -3
- data/spec/acceptance/paginating_search_results_spec.rb +3 -3
- data/spec/acceptance/real_time_updates_spec.rb +4 -4
- data/spec/acceptance/remove_deleted_records_spec.rb +12 -12
- data/spec/acceptance/search_counts_spec.rb +2 -2
- data/spec/acceptance/search_for_just_ids_spec.rb +2 -2
- data/spec/acceptance/searching_across_models_spec.rb +6 -6
- data/spec/acceptance/searching_across_schemas_spec.rb +10 -10
- data/spec/acceptance/searching_on_fields_spec.rb +9 -9
- data/spec/acceptance/searching_with_filters_spec.rb +16 -16
- data/spec/acceptance/searching_with_sti_spec.rb +9 -9
- data/spec/acceptance/searching_within_a_model_spec.rb +17 -17
- data/spec/acceptance/sorting_search_results_spec.rb +6 -6
- data/spec/acceptance/specifying_sql_spec.rb +62 -62
- data/spec/acceptance/sphinx_scopes_spec.rb +9 -9
- data/spec/acceptance/sql_deltas_spec.rb +7 -7
- data/spec/acceptance/support/database_cleaner.rb +1 -1
- data/spec/acceptance/support/sphinx_controller.rb +4 -1
- data/spec/acceptance/support/sphinx_helpers.rb +4 -0
- data/spec/acceptance/suspended_deltas_spec.rb +9 -9
- data/spec/internal/app/indices/article_index.rb +2 -2
- data/spec/internal/app/indices/book_index.rb +2 -1
- data/spec/internal/app/indices/product_index.rb +0 -2
- data/spec/internal/app/models/categorisation.rb +8 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/support/json_column.rb +5 -1
- data/spec/support/multi_schema.rb +3 -1
- data/spec/support/sphinx_yaml_helpers.rb +1 -1
- data/spec/thinking_sphinx/active_record/association_spec.rb +1 -1
- data/spec/thinking_sphinx/active_record/attribute/type_spec.rb +41 -38
- data/spec/thinking_sphinx/active_record/base_spec.rb +29 -29
- data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +10 -10
- data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +48 -25
- data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +8 -8
- data/spec/thinking_sphinx/active_record/column_spec.rb +13 -13
- data/spec/thinking_sphinx/active_record/column_sql_presenter_spec.rb +5 -5
- data/spec/thinking_sphinx/active_record/database_adapters/abstract_adapter_spec.rb +5 -5
- data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +11 -11
- data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +13 -13
- data/spec/thinking_sphinx/active_record/database_adapters_spec.rb +48 -48
- data/spec/thinking_sphinx/active_record/field_spec.rb +7 -7
- data/spec/thinking_sphinx/active_record/filter_reflection_spec.rb +32 -32
- data/spec/thinking_sphinx/active_record/index_spec.rb +35 -36
- data/spec/thinking_sphinx/active_record/interpreter_spec.rb +51 -51
- data/spec/thinking_sphinx/active_record/polymorpher_spec.rb +14 -14
- data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +67 -67
- data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +140 -140
- data/spec/thinking_sphinx/active_record/sql_source_spec.rb +97 -95
- data/spec/thinking_sphinx/configuration_spec.rb +81 -81
- data/spec/thinking_sphinx/connection_spec.rb +13 -13
- data/spec/thinking_sphinx/deletion_spec.rb +11 -11
- data/spec/thinking_sphinx/deltas/default_delta_spec.rb +20 -20
- data/spec/thinking_sphinx/deltas_spec.rb +12 -12
- data/spec/thinking_sphinx/errors_spec.rb +30 -30
- data/spec/thinking_sphinx/excerpter_spec.rb +7 -7
- data/spec/thinking_sphinx/facet_search_spec.rb +16 -16
- data/spec/thinking_sphinx/index_set_spec.rb +7 -7
- data/spec/thinking_sphinx/index_spec.rb +24 -24
- data/spec/thinking_sphinx/masks/pagination_mask_spec.rb +20 -20
- data/spec/thinking_sphinx/masks/scopes_mask_spec.rb +18 -18
- data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +22 -22
- data/spec/thinking_sphinx/middlewares/geographer_spec.rb +9 -9
- data/spec/thinking_sphinx/middlewares/glazier_spec.rb +4 -4
- data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +7 -7
- data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +53 -53
- data/spec/thinking_sphinx/middlewares/stale_id_checker_spec.rb +5 -5
- data/spec/thinking_sphinx/middlewares/stale_id_filter_spec.rb +15 -15
- data/spec/thinking_sphinx/panes/attributes_pane_spec.rb +1 -1
- data/spec/thinking_sphinx/panes/distance_pane_spec.rb +4 -4
- data/spec/thinking_sphinx/panes/excerpts_pane_spec.rb +5 -5
- data/spec/thinking_sphinx/panes/weight_pane_spec.rb +1 -1
- data/spec/thinking_sphinx/rake_interface_spec.rb +66 -53
- data/spec/thinking_sphinx/real_time/attribute_spec.rb +13 -13
- data/spec/thinking_sphinx/real_time/callbacks/real_time_callbacks_spec.rb +107 -23
- data/spec/thinking_sphinx/real_time/field_spec.rb +14 -14
- data/spec/thinking_sphinx/real_time/index_spec.rb +29 -30
- data/spec/thinking_sphinx/real_time/interpreter_spec.rb +30 -30
- data/spec/thinking_sphinx/scopes_spec.rb +5 -5
- data/spec/thinking_sphinx/search/glaze_spec.rb +15 -15
- data/spec/thinking_sphinx/search/query_spec.rb +10 -10
- data/spec/thinking_sphinx/search_spec.rb +28 -28
- data/spec/thinking_sphinx/wildcard_spec.rb +16 -11
- data/spec/thinking_sphinx_spec.rb +6 -6
- data/thinking-sphinx.gemspec +4 -4
- metadata +12 -9
|
@@ -7,7 +7,7 @@ describe 'Sorting search results', :live => true do
|
|
|
7
7
|
boys = Book.create! :title => 'Anansi Boys', :year => 2005
|
|
8
8
|
index
|
|
9
9
|
|
|
10
|
-
Book.search(:order => 'year ASC').to_a.
|
|
10
|
+
expect(Book.search(:order => 'year ASC').to_a).to eq([gods, boys, grave])
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it "sorts by a given attribute in ascending order" do
|
|
@@ -16,7 +16,7 @@ describe 'Sorting search results', :live => true do
|
|
|
16
16
|
boys = Book.create! :title => 'Anansi Boys', :year => 2005
|
|
17
17
|
index
|
|
18
18
|
|
|
19
|
-
Book.search(:order => :year).to_a.
|
|
19
|
+
expect(Book.search(:order => :year).to_a).to eq([gods, boys, grave])
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
it "sorts by a given sortable field" do
|
|
@@ -25,14 +25,14 @@ describe 'Sorting search results', :live => true do
|
|
|
25
25
|
boys = Book.create! :title => 'Anansi Boys', :year => 2005
|
|
26
26
|
index
|
|
27
27
|
|
|
28
|
-
Book.search(:order => :title).to_a.
|
|
28
|
+
expect(Book.search(:order => :title).to_a).to eq([gods, boys, grave])
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "sorts by a given sortable field with real-time indices" do
|
|
32
32
|
widgets = Product.create! :name => 'Widgets'
|
|
33
33
|
gadgets = Product.create! :name => 'Gadgets'
|
|
34
34
|
|
|
35
|
-
Product.search(:order => "name_sort ASC").to_a.
|
|
35
|
+
expect(Product.search(:order => "name_sort ASC").to_a).to eq([gadgets, widgets])
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
it "can sort with a provided expression" do
|
|
@@ -41,8 +41,8 @@ describe 'Sorting search results', :live => true do
|
|
|
41
41
|
boys = Book.create! :title => 'Anansi Boys', :year => 2005
|
|
42
42
|
index
|
|
43
43
|
|
|
44
|
-
Book.search(
|
|
44
|
+
expect(Book.search(
|
|
45
45
|
:select => '*, year MOD 2004 as mod_year', :order => 'mod_year ASC'
|
|
46
|
-
).to_a.
|
|
46
|
+
).to_a).to eq([boys, grave, gods])
|
|
47
47
|
end
|
|
48
48
|
end
|
|
@@ -8,7 +8,7 @@ describe 'specifying SQL for index definitions' do
|
|
|
8
8
|
join user
|
|
9
9
|
}
|
|
10
10
|
index.render
|
|
11
|
-
index.sources.first.sql_query.
|
|
11
|
+
expect(index.sources.first.sql_query).to match(/LEFT OUTER JOIN .users./)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it "handles deep joins" do
|
|
@@ -20,8 +20,8 @@ describe 'specifying SQL for index definitions' do
|
|
|
20
20
|
index.render
|
|
21
21
|
|
|
22
22
|
query = index.sources.first.sql_query
|
|
23
|
-
query.
|
|
24
|
-
query.
|
|
23
|
+
expect(query).to match(/LEFT OUTER JOIN .users./)
|
|
24
|
+
expect(query).to match(/LEFT OUTER JOIN .articles./)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
it "handles has-many :through joins" do
|
|
@@ -32,8 +32,8 @@ describe 'specifying SQL for index definitions' do
|
|
|
32
32
|
index.render
|
|
33
33
|
|
|
34
34
|
query = index.sources.first.sql_query
|
|
35
|
-
query.
|
|
36
|
-
query.
|
|
35
|
+
expect(query).to match(/LEFT OUTER JOIN .taggings./)
|
|
36
|
+
expect(query).to match(/LEFT OUTER JOIN .tags./)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
it "handles custom join SQL statements" do
|
|
@@ -45,7 +45,7 @@ describe 'specifying SQL for index definitions' do
|
|
|
45
45
|
index.render
|
|
46
46
|
|
|
47
47
|
query = index.sources.first.sql_query
|
|
48
|
-
query.
|
|
48
|
+
expect(query).to match(/INNER JOIN foo ON foo.x = bar.y/)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
it "handles GROUP BY clauses" do
|
|
@@ -57,7 +57,7 @@ describe 'specifying SQL for index definitions' do
|
|
|
57
57
|
index.render
|
|
58
58
|
|
|
59
59
|
query = index.sources.first.sql_query
|
|
60
|
-
query.
|
|
60
|
+
expect(query).to match(/GROUP BY .articles.\..id., .?articles.?\..title., .?articles.?\..id., lat/)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
it "handles WHERE clauses" do
|
|
@@ -69,7 +69,7 @@ describe 'specifying SQL for index definitions' do
|
|
|
69
69
|
index.render
|
|
70
70
|
|
|
71
71
|
query = index.sources.first.sql_query
|
|
72
|
-
query.
|
|
72
|
+
expect(query).to match(/WHERE .+title != 'secret'.+ GROUP BY/)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
it "handles manual MVA declarations" do
|
|
@@ -81,7 +81,7 @@ describe 'specifying SQL for index definitions' do
|
|
|
81
81
|
}
|
|
82
82
|
index.render
|
|
83
83
|
|
|
84
|
-
index.sources.first.sql_attr_multi.
|
|
84
|
+
expect(index.sources.first.sql_attr_multi).to eq(['uint tag_ids from field'])
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
it "provides the sanitize_sql helper within the index definition block" do
|
|
@@ -93,7 +93,7 @@ describe 'specifying SQL for index definitions' do
|
|
|
93
93
|
index.render
|
|
94
94
|
|
|
95
95
|
query = index.sources.first.sql_query
|
|
96
|
-
query.
|
|
96
|
+
expect(query).to match(/WHERE .+title != 'secret'.+ GROUP BY/)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
it "escapes new lines in SQL snippets" do
|
|
@@ -111,7 +111,7 @@ describe 'specifying SQL for index definitions' do
|
|
|
111
111
|
index.render
|
|
112
112
|
|
|
113
113
|
query = index.sources.first.sql_query
|
|
114
|
-
query.
|
|
114
|
+
expect(query).to match(/\\\n/)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
it "joins each polymorphic relation" do
|
|
@@ -123,9 +123,9 @@ describe 'specifying SQL for index definitions' do
|
|
|
123
123
|
index.render
|
|
124
124
|
|
|
125
125
|
query = index.sources.first.sql_query
|
|
126
|
-
query.
|
|
127
|
-
query.
|
|
128
|
-
query.
|
|
126
|
+
expect(query).to match(/LEFT OUTER JOIN .articles. ON .articles.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Article'/)
|
|
127
|
+
expect(query).to match(/LEFT OUTER JOIN .books. ON .books.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Book'/)
|
|
128
|
+
expect(query).to match(/.articles.\..title., .books.\..title./)
|
|
129
129
|
end if ActiveRecord::VERSION::MAJOR > 3
|
|
130
130
|
|
|
131
131
|
it "concatenates references that have column" do
|
|
@@ -137,9 +137,9 @@ describe 'specifying SQL for index definitions' do
|
|
|
137
137
|
index.render
|
|
138
138
|
|
|
139
139
|
query = index.sources.first.sql_query
|
|
140
|
-
query.
|
|
141
|
-
query.
|
|
142
|
-
query.
|
|
140
|
+
expect(query).to match(/LEFT OUTER JOIN .articles. ON .articles.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Article'/)
|
|
141
|
+
expect(query).not_to match(/articles\..title., users\..title./)
|
|
142
|
+
expect(query).to match(/.articles.\..title./)
|
|
143
143
|
end if ActiveRecord::VERSION::MAJOR > 3
|
|
144
144
|
|
|
145
145
|
it "respects deeper associations through polymorphic joins" do
|
|
@@ -151,9 +151,9 @@ describe 'specifying SQL for index definitions' do
|
|
|
151
151
|
index.render
|
|
152
152
|
|
|
153
153
|
query = index.sources.first.sql_query
|
|
154
|
-
query.
|
|
155
|
-
query.
|
|
156
|
-
query.
|
|
154
|
+
expect(query).to match(/LEFT OUTER JOIN .articles. ON .articles.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Article'/)
|
|
155
|
+
expect(query).to match(/LEFT OUTER JOIN .users. ON .users.\..id. = .articles.\..user_id./)
|
|
156
|
+
expect(query).to match(/.users.\..name./)
|
|
157
157
|
end
|
|
158
158
|
end if ActiveRecord::VERSION::MAJOR > 3
|
|
159
159
|
|
|
@@ -174,8 +174,8 @@ describe 'separate queries for MVAs' do
|
|
|
174
174
|
}
|
|
175
175
|
declaration, query = attribute.split(/;\s+/)
|
|
176
176
|
|
|
177
|
-
declaration.
|
|
178
|
-
query.
|
|
177
|
+
expect(declaration).to eq('uint tag_ids from query')
|
|
178
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)$/)
|
|
179
179
|
end
|
|
180
180
|
|
|
181
181
|
it "generates a SQL query with joins when appropriate for MVAs" do
|
|
@@ -190,8 +190,8 @@ describe 'separate queries for MVAs' do
|
|
|
190
190
|
}
|
|
191
191
|
declaration, query = attribute.split(/;\s+/)
|
|
192
192
|
|
|
193
|
-
declaration.
|
|
194
|
-
query.
|
|
193
|
+
expect(declaration).to eq('uint tag_ids from query')
|
|
194
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
|
|
195
195
|
end
|
|
196
196
|
|
|
197
197
|
it "respects has_many :through joins for MVA queries" do
|
|
@@ -206,8 +206,8 @@ describe 'separate queries for MVAs' do
|
|
|
206
206
|
}
|
|
207
207
|
declaration, query = attribute.split(/;\s+/)
|
|
208
208
|
|
|
209
|
-
declaration.
|
|
210
|
-
query.
|
|
209
|
+
expect(declaration).to eq('uint tag_ids from query')
|
|
210
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
|
|
211
211
|
end
|
|
212
212
|
|
|
213
213
|
it "can handle multiple joins for MVA queries" do
|
|
@@ -224,8 +224,8 @@ describe 'separate queries for MVAs' do
|
|
|
224
224
|
}
|
|
225
225
|
declaration, query = attribute.split(/;\s+/)
|
|
226
226
|
|
|
227
|
-
declaration.
|
|
228
|
-
query.
|
|
227
|
+
expect(declaration).to eq('uint tag_ids from query')
|
|
228
|
+
expect(query).to match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.articles.\..user_id. IS NOT NULL\)\s?$/)
|
|
229
229
|
end
|
|
230
230
|
|
|
231
231
|
it "can handle simple HABTM joins for MVA queries" do
|
|
@@ -242,8 +242,8 @@ describe 'separate queries for MVAs' do
|
|
|
242
242
|
}
|
|
243
243
|
declaration, query = attribute.split(/;\s+/)
|
|
244
244
|
|
|
245
|
-
declaration.
|
|
246
|
-
query.
|
|
245
|
+
expect(declaration).to eq('uint genre_ids from query')
|
|
246
|
+
expect(query).to match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres.\s?$/)
|
|
247
247
|
end if ActiveRecord::VERSION::MAJOR > 3
|
|
248
248
|
|
|
249
249
|
it "generates an appropriate range SQL queries for an MVA" do
|
|
@@ -258,9 +258,9 @@ describe 'separate queries for MVAs' do
|
|
|
258
258
|
}
|
|
259
259
|
declaration, query, range = attribute.split(/;\s+/)
|
|
260
260
|
|
|
261
|
-
declaration.
|
|
262
|
-
query.
|
|
263
|
-
range.
|
|
261
|
+
expect(declaration).to eq('uint tag_ids from ranged-query')
|
|
262
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
|
|
263
|
+
expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
|
264
264
|
end
|
|
265
265
|
|
|
266
266
|
it "generates a SQL query with joins when appropriate for MVAs" do
|
|
@@ -275,9 +275,9 @@ describe 'separate queries for MVAs' do
|
|
|
275
275
|
}
|
|
276
276
|
declaration, query, range = attribute.split(/;\s+/)
|
|
277
277
|
|
|
278
|
-
declaration.
|
|
279
|
-
query.
|
|
280
|
-
range.
|
|
278
|
+
expect(declaration).to eq('uint tag_ids from ranged-query')
|
|
279
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
|
|
280
|
+
expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
|
281
281
|
end
|
|
282
282
|
|
|
283
283
|
it "can handle ranged queries for simple HABTM joins for MVA queries" do
|
|
@@ -294,9 +294,9 @@ describe 'separate queries for MVAs' do
|
|
|
294
294
|
}
|
|
295
295
|
declaration, query, range = attribute.split(/;\s+/)
|
|
296
296
|
|
|
297
|
-
declaration.
|
|
298
|
-
query.
|
|
299
|
-
range.
|
|
297
|
+
expect(declaration).to eq('uint genre_ids from ranged-query')
|
|
298
|
+
expect(query).to match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres. WHERE \(.books_genres.\..book_id. BETWEEN \$start AND \$end\)$/)
|
|
299
|
+
expect(range).to match(/^SELECT MIN\(.books_genres.\..book_id.\), MAX\(.books_genres.\..book_id.\) FROM .books_genres.$/)
|
|
300
300
|
end if ActiveRecord::VERSION::MAJOR > 3
|
|
301
301
|
|
|
302
302
|
it "respects custom SQL snippets as the query value" do
|
|
@@ -312,8 +312,8 @@ describe 'separate queries for MVAs' do
|
|
|
312
312
|
}
|
|
313
313
|
declaration, query = attribute.split(/;\s+/)
|
|
314
314
|
|
|
315
|
-
declaration.
|
|
316
|
-
query.
|
|
315
|
+
expect(declaration).to eq('uint tag_ids from query')
|
|
316
|
+
expect(query).to eq('My Custom SQL Query')
|
|
317
317
|
end
|
|
318
318
|
|
|
319
319
|
it "respects custom SQL snippets as the ranged query value" do
|
|
@@ -329,9 +329,9 @@ describe 'separate queries for MVAs' do
|
|
|
329
329
|
}
|
|
330
330
|
declaration, query, range = attribute.split(/;\s+/)
|
|
331
331
|
|
|
332
|
-
declaration.
|
|
333
|
-
query.
|
|
334
|
-
range.
|
|
332
|
+
expect(declaration).to eq('uint tag_ids from ranged-query')
|
|
333
|
+
expect(query).to eq('My Custom SQL Query')
|
|
334
|
+
expect(range).to eq('And a Range')
|
|
335
335
|
end
|
|
336
336
|
|
|
337
337
|
it "escapes new lines in custom SQL snippets" do
|
|
@@ -349,8 +349,8 @@ SQL Query
|
|
|
349
349
|
}
|
|
350
350
|
declaration, query = attribute.split(/;\s+/)
|
|
351
351
|
|
|
352
|
-
declaration.
|
|
353
|
-
query.
|
|
352
|
+
expect(declaration).to eq('uint tag_ids from query')
|
|
353
|
+
expect(query).to eq("My Custom\\\nSQL Query")
|
|
354
354
|
end
|
|
355
355
|
end
|
|
356
356
|
|
|
@@ -368,8 +368,8 @@ describe 'separate queries for field' do
|
|
|
368
368
|
field = source.sql_joined_field.detect { |field| field[/tags/] }
|
|
369
369
|
declaration, query = field.split(/;\s+/)
|
|
370
370
|
|
|
371
|
-
declaration.
|
|
372
|
-
query.
|
|
371
|
+
expect(declaration).to eq('tags from query')
|
|
372
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
|
|
373
373
|
end
|
|
374
374
|
|
|
375
375
|
it "respects has_many :through joins for MVF queries" do
|
|
@@ -381,8 +381,8 @@ describe 'separate queries for field' do
|
|
|
381
381
|
field = source.sql_joined_field.detect { |field| field[/tags/] }
|
|
382
382
|
declaration, query = field.split(/;\s+/)
|
|
383
383
|
|
|
384
|
-
declaration.
|
|
385
|
-
query.
|
|
384
|
+
expect(declaration).to eq('tags from query')
|
|
385
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
|
|
386
386
|
end
|
|
387
387
|
|
|
388
388
|
it "can handle multiple joins for MVF queries" do
|
|
@@ -396,8 +396,8 @@ describe 'separate queries for field' do
|
|
|
396
396
|
field = source.sql_joined_field.detect { |field| field[/tags/] }
|
|
397
397
|
declaration, query = field.split(/;\s+/)
|
|
398
398
|
|
|
399
|
-
declaration.
|
|
400
|
-
query.
|
|
399
|
+
expect(declaration).to eq('tags from query')
|
|
400
|
+
expect(query).to match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.articles.\..user_id. IS NOT NULL\)\s? ORDER BY .articles.\..user_id. ASC\s?$/)
|
|
401
401
|
end
|
|
402
402
|
|
|
403
403
|
it "generates a SQL query with joins when appropriate for MVFs" do
|
|
@@ -409,9 +409,9 @@ describe 'separate queries for field' do
|
|
|
409
409
|
field = source.sql_joined_field.detect { |field| field[/tags/] }
|
|
410
410
|
declaration, query, range = field.split(/;\s+/)
|
|
411
411
|
|
|
412
|
-
declaration.
|
|
413
|
-
query.
|
|
414
|
-
range.
|
|
412
|
+
expect(declaration).to eq('tags from ranged-query')
|
|
413
|
+
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC$/)
|
|
414
|
+
expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
|
415
415
|
end
|
|
416
416
|
|
|
417
417
|
it "respects custom SQL snippets as the query value" do
|
|
@@ -423,8 +423,8 @@ describe 'separate queries for field' do
|
|
|
423
423
|
field = source.sql_joined_field.detect { |field| field[/tags/] }
|
|
424
424
|
declaration, query = field.split(/;\s+/)
|
|
425
425
|
|
|
426
|
-
declaration.
|
|
427
|
-
query.
|
|
426
|
+
expect(declaration).to eq('tags from query')
|
|
427
|
+
expect(query).to eq('My Custom SQL Query')
|
|
428
428
|
end
|
|
429
429
|
|
|
430
430
|
it "respects custom SQL snippets as the ranged query value" do
|
|
@@ -437,9 +437,9 @@ describe 'separate queries for field' do
|
|
|
437
437
|
field = source.sql_joined_field.detect { |field| field[/tags/] }
|
|
438
438
|
declaration, query, range = field.split(/;\s+/)
|
|
439
439
|
|
|
440
|
-
declaration.
|
|
441
|
-
query.
|
|
442
|
-
range.
|
|
440
|
+
expect(declaration).to eq('tags from ranged-query')
|
|
441
|
+
expect(query).to eq('My Custom SQL Query')
|
|
442
|
+
expect(range).to eq('And a Range')
|
|
443
443
|
end
|
|
444
444
|
|
|
445
445
|
it "escapes new lines in custom SQL snippets" do
|
|
@@ -454,7 +454,7 @@ SQL Query
|
|
|
454
454
|
field = source.sql_joined_field.detect { |field| field[/tags/] }
|
|
455
455
|
declaration, query = field.split(/;\s+/)
|
|
456
456
|
|
|
457
|
-
declaration.
|
|
458
|
-
query.
|
|
457
|
+
expect(declaration).to eq('tags from query')
|
|
458
|
+
expect(query).to eq("My Custom\\\nSQL Query")
|
|
459
459
|
end
|
|
460
460
|
end
|
|
@@ -7,7 +7,7 @@ describe 'Sphinx scopes', :live => true do
|
|
|
7
7
|
grave = Book.create! :title => 'The Graveyard Book', :year => 2009
|
|
8
8
|
index
|
|
9
9
|
|
|
10
|
-
Book.by_year(2009).to_a.
|
|
10
|
+
expect(Book.by_year(2009).to_a).to eq([grave])
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it "allows scopes to return both query and options" do
|
|
@@ -16,7 +16,7 @@ describe 'Sphinx scopes', :live => true do
|
|
|
16
16
|
grave = Book.create! :title => 'The Graveyard Book', :year => 2009
|
|
17
17
|
index
|
|
18
18
|
|
|
19
|
-
Book.by_query_and_year('Graveyard', 2009).to_a.
|
|
19
|
+
expect(Book.by_query_and_year('Graveyard', 2009).to_a).to eq([grave])
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
it "allows chaining of scopes" do
|
|
@@ -25,7 +25,7 @@ describe 'Sphinx scopes', :live => true do
|
|
|
25
25
|
grave = Book.create! :title => 'The Graveyard Book', :year => 2009
|
|
26
26
|
index
|
|
27
27
|
|
|
28
|
-
Book.by_year(2001..2005).ordered.to_a.
|
|
28
|
+
expect(Book.by_year(2001..2005).ordered.to_a).to eq([boys, gods])
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "allows chaining of scopes that include queries" do
|
|
@@ -34,8 +34,8 @@ describe 'Sphinx scopes', :live => true do
|
|
|
34
34
|
grave = Book.create! :title => 'The Graveyard Book', :year => 2009
|
|
35
35
|
index
|
|
36
36
|
|
|
37
|
-
Book.by_year(2001).by_query_and_year('Graveyard', 2009).to_a.
|
|
38
|
-
|
|
37
|
+
expect(Book.by_year(2001).by_query_and_year('Graveyard', 2009).to_a).
|
|
38
|
+
to eq([grave])
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
it "allows further search calls on scopes" do
|
|
@@ -43,7 +43,7 @@ describe 'Sphinx scopes', :live => true do
|
|
|
43
43
|
pratchett = Book.create! :title => 'Small Gods'
|
|
44
44
|
index
|
|
45
45
|
|
|
46
|
-
Book.by_query('Gods').search('Small').to_a.
|
|
46
|
+
expect(Book.by_query('Gods').search('Small').to_a).to eq([pratchett])
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
it "allows facet calls on scopes" do
|
|
@@ -52,9 +52,9 @@ describe 'Sphinx scopes', :live => true do
|
|
|
52
52
|
Book.create! :title => 'Small Gods', :author => 'Terry Pratchett'
|
|
53
53
|
index
|
|
54
54
|
|
|
55
|
-
Book.by_query('Gods').facets.to_hash[:author].
|
|
55
|
+
expect(Book.by_query('Gods').facets.to_hash[:author]).to eq({
|
|
56
56
|
'Neil Gaiman' => 1, 'Terry Pratchett' => 1
|
|
57
|
-
}
|
|
57
|
+
})
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
it "allows accessing counts on scopes" do
|
|
@@ -64,7 +64,7 @@ describe 'Sphinx scopes', :live => true do
|
|
|
64
64
|
Book.create! :title => 'Night Watch'
|
|
65
65
|
index
|
|
66
66
|
|
|
67
|
-
Book.by_query('gods').count.
|
|
67
|
+
expect(Book.by_query('gods').count).to eq(2)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
it 'raises an exception when trying to modify a populated request' do
|
|
@@ -7,38 +7,38 @@ describe 'SQL delta indexing', :live => true do
|
|
|
7
7
|
)
|
|
8
8
|
index
|
|
9
9
|
|
|
10
|
-
Book.search('Terry Pratchett').to_a.
|
|
10
|
+
expect(Book.search('Terry Pratchett').to_a).to eq([guards])
|
|
11
11
|
|
|
12
12
|
men = Book.create(
|
|
13
13
|
:title => 'Men At Arms', :author => 'Terry Pratchett'
|
|
14
14
|
)
|
|
15
15
|
sleep 0.25
|
|
16
16
|
|
|
17
|
-
Book.search('Terry Pratchett').to_a.
|
|
17
|
+
expect(Book.search('Terry Pratchett').to_a).to eq([guards, men])
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
it "automatically indexes updated records" do
|
|
21
21
|
book = Book.create :title => 'Night Watch', :author => 'Harry Pritchett'
|
|
22
22
|
index
|
|
23
23
|
|
|
24
|
-
Book.search('Harry').to_a.
|
|
24
|
+
expect(Book.search('Harry').to_a).to eq([book])
|
|
25
25
|
|
|
26
26
|
book.reload.update_attributes(:author => 'Terry Pratchett')
|
|
27
27
|
sleep 0.25
|
|
28
28
|
|
|
29
|
-
Book.search('Terry').to_a.
|
|
29
|
+
expect(Book.search('Terry').to_a).to eq([book])
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
it "does not match on old values" do
|
|
33
33
|
book = Book.create :title => 'Night Watch', :author => 'Harry Pritchett'
|
|
34
34
|
index
|
|
35
35
|
|
|
36
|
-
Book.search('Harry').to_a.
|
|
36
|
+
expect(Book.search('Harry').to_a).to eq([book])
|
|
37
37
|
|
|
38
38
|
book.reload.update_attributes(:author => 'Terry Pratchett')
|
|
39
39
|
sleep 0.25
|
|
40
40
|
|
|
41
|
-
Book.search('Harry').
|
|
41
|
+
expect(Book.search('Harry')).to be_empty
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
it "automatically indexes new records of subclasses" do
|
|
@@ -47,6 +47,6 @@ describe 'SQL delta indexing', :live => true do
|
|
|
47
47
|
)
|
|
48
48
|
sleep 0.25
|
|
49
49
|
|
|
50
|
-
Book.search('Gaiman').to_a.
|
|
50
|
+
expect(Book.search('Gaiman').to_a).to eq([book])
|
|
51
51
|
end
|
|
52
52
|
end
|