thinking-sphinx 2.0.5 → 2.0.6
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 +7 -1
- data/features/searching_by_model.feature +24 -30
- data/features/step_definitions/common_steps.rb +5 -5
- data/features/thinking_sphinx/db/.gitignore +1 -0
- data/features/thinking_sphinx/db/fixtures/post_keywords.txt +1 -0
- data/spec/fixtures/data.sql +32 -0
- data/spec/fixtures/database.yml.default +3 -0
- data/spec/fixtures/models.rb +161 -0
- data/spec/fixtures/structure.sql +146 -0
- data/spec/spec_helper.rb +62 -0
- data/spec/sphinx_helper.rb +61 -0
- data/spec/support/rails.rb +18 -0
- data/spec/thinking_sphinx/active_record/delta_spec.rb +24 -24
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +27 -0
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +25 -25
- data/spec/thinking_sphinx/active_record_spec.rb +108 -107
- data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +38 -38
- data/spec/thinking_sphinx/association_spec.rb +69 -35
- data/spec/thinking_sphinx/context_spec.rb +61 -64
- data/spec/thinking_sphinx/search_spec.rb +7 -0
- data/spec/thinking_sphinx_spec.rb +47 -46
- metadata +49 -141
- data/VERSION +0 -1
- data/lib/cucumber/thinking_sphinx/external_world.rb +0 -12
- data/lib/cucumber/thinking_sphinx/internal_world.rb +0 -127
- data/lib/cucumber/thinking_sphinx/sql_logger.rb +0 -20
- data/lib/thinking-sphinx.rb +0 -1
- data/lib/thinking_sphinx.rb +0 -301
- data/lib/thinking_sphinx/action_controller.rb +0 -31
- data/lib/thinking_sphinx/active_record.rb +0 -384
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +0 -52
- data/lib/thinking_sphinx/active_record/delta.rb +0 -65
- data/lib/thinking_sphinx/active_record/has_many_association.rb +0 -36
- data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +0 -21
- data/lib/thinking_sphinx/active_record/log_subscriber.rb +0 -61
- data/lib/thinking_sphinx/active_record/scopes.rb +0 -93
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +0 -87
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +0 -62
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +0 -157
- data/lib/thinking_sphinx/association.rb +0 -219
- data/lib/thinking_sphinx/attribute.rb +0 -396
- data/lib/thinking_sphinx/auto_version.rb +0 -38
- data/lib/thinking_sphinx/bundled_search.rb +0 -44
- data/lib/thinking_sphinx/class_facet.rb +0 -20
- data/lib/thinking_sphinx/configuration.rb +0 -339
- data/lib/thinking_sphinx/context.rb +0 -76
- data/lib/thinking_sphinx/core/string.rb +0 -15
- data/lib/thinking_sphinx/deltas.rb +0 -28
- data/lib/thinking_sphinx/deltas/default_delta.rb +0 -62
- data/lib/thinking_sphinx/deploy/capistrano.rb +0 -101
- data/lib/thinking_sphinx/excerpter.rb +0 -23
- data/lib/thinking_sphinx/facet.rb +0 -128
- data/lib/thinking_sphinx/facet_search.rb +0 -170
- data/lib/thinking_sphinx/field.rb +0 -98
- data/lib/thinking_sphinx/index.rb +0 -157
- data/lib/thinking_sphinx/index/builder.rb +0 -312
- data/lib/thinking_sphinx/index/faux_column.rb +0 -118
- data/lib/thinking_sphinx/join.rb +0 -37
- data/lib/thinking_sphinx/property.rb +0 -185
- data/lib/thinking_sphinx/railtie.rb +0 -46
- data/lib/thinking_sphinx/search.rb +0 -972
- data/lib/thinking_sphinx/search_methods.rb +0 -439
- data/lib/thinking_sphinx/sinatra.rb +0 -7
- data/lib/thinking_sphinx/source.rb +0 -194
- data/lib/thinking_sphinx/source/internal_properties.rb +0 -51
- data/lib/thinking_sphinx/source/sql.rb +0 -157
- data/lib/thinking_sphinx/tasks.rb +0 -130
- data/lib/thinking_sphinx/test.rb +0 -55
- data/tasks/distribution.rb +0 -33
- data/tasks/testing.rb +0 -80
@@ -1,98 +0,0 @@
|
|
1
|
-
module ThinkingSphinx
|
2
|
-
# Fields - holding the string data which Sphinx indexes for your searches.
|
3
|
-
# This class isn't really useful to you unless you're hacking around with the
|
4
|
-
# internals of Thinking Sphinx - but hey, don't let that stop you.
|
5
|
-
#
|
6
|
-
# One key thing to remember - if you're using the field manually to
|
7
|
-
# generate SQL statements, you'll need to set the base model, and all the
|
8
|
-
# associations. Which can get messy. Use Index.link!, it really helps.
|
9
|
-
#
|
10
|
-
class Field < ThinkingSphinx::Property
|
11
|
-
attr_accessor :sortable, :infixes, :prefixes
|
12
|
-
|
13
|
-
# To create a new field, you'll need to pass in either a single Column
|
14
|
-
# or an array of them, and some (optional) options. The columns are
|
15
|
-
# references to the data that will make up the field.
|
16
|
-
#
|
17
|
-
# Valid options are:
|
18
|
-
# - :as => :alias_name
|
19
|
-
# - :sortable => true
|
20
|
-
# - :infixes => true
|
21
|
-
# - :prefixes => true
|
22
|
-
# - :file => true
|
23
|
-
# - :with => :attribute # or :wordcount
|
24
|
-
#
|
25
|
-
# Alias is only required in three circumstances: when there's
|
26
|
-
# another attribute or field with the same name, when the column name is
|
27
|
-
# 'id', or when there's more than one column.
|
28
|
-
#
|
29
|
-
# Sortable defaults to false - but is quite useful when set to true, as
|
30
|
-
# it creates an attribute with the same string value (which Sphinx converts
|
31
|
-
# to an integer value), which can be sorted by. Thinking Sphinx is smart
|
32
|
-
# enough to realise that when you specify fields in sort statements, you
|
33
|
-
# mean their respective attributes.
|
34
|
-
#
|
35
|
-
# If you have partial matching enabled (ie: enable_star), then you can
|
36
|
-
# specify certain fields to have their prefixes and infixes indexed. Keep
|
37
|
-
# in mind, though, that Sphinx's default is _all_ fields - so once you
|
38
|
-
# highlight a particular field, no other fields in the index will have
|
39
|
-
# these partial indexes.
|
40
|
-
#
|
41
|
-
# Here's some examples:
|
42
|
-
#
|
43
|
-
# Field.new(
|
44
|
-
# Column.new(:name)
|
45
|
-
# )
|
46
|
-
#
|
47
|
-
# Field.new(
|
48
|
-
# [Column.new(:first_name), Column.new(:last_name)],
|
49
|
-
# :as => :name, :sortable => true
|
50
|
-
# )
|
51
|
-
#
|
52
|
-
# Field.new(
|
53
|
-
# [Column.new(:posts, :subject), Column.new(:posts, :content)],
|
54
|
-
# :as => :posts, :prefixes => true
|
55
|
-
# )
|
56
|
-
#
|
57
|
-
def initialize(source, columns, options = {})
|
58
|
-
super
|
59
|
-
|
60
|
-
@sortable = options[:sortable] || false
|
61
|
-
@infixes = options[:infixes] || false
|
62
|
-
@prefixes = options[:prefixes] || false
|
63
|
-
@file = options[:file] || false
|
64
|
-
@with = options[:with]
|
65
|
-
|
66
|
-
source.fields << self
|
67
|
-
end
|
68
|
-
|
69
|
-
# Get the part of the SELECT clause related to this field. Don't forget
|
70
|
-
# to set your model and associations first though.
|
71
|
-
#
|
72
|
-
# This will concatenate strings if there's more than one data source or
|
73
|
-
# multiple data values (has_many or has_and_belongs_to_many associations).
|
74
|
-
#
|
75
|
-
def to_select_sql
|
76
|
-
return nil unless available?
|
77
|
-
|
78
|
-
clause = columns_with_prefixes.join(', ')
|
79
|
-
|
80
|
-
clause = adapter.concatenate(clause) if concat_ws?
|
81
|
-
clause = adapter.group_concatenate(clause) if is_many?
|
82
|
-
|
83
|
-
"#{clause} AS #{quote_column(unique_name)}"
|
84
|
-
end
|
85
|
-
|
86
|
-
def file?
|
87
|
-
@file
|
88
|
-
end
|
89
|
-
|
90
|
-
def with_attribute?
|
91
|
-
@with == :attribute
|
92
|
-
end
|
93
|
-
|
94
|
-
def with_wordcount?
|
95
|
-
@with == :wordcount
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,157 +0,0 @@
|
|
1
|
-
require 'thinking_sphinx/index/builder'
|
2
|
-
require 'thinking_sphinx/index/faux_column'
|
3
|
-
|
4
|
-
module ThinkingSphinx
|
5
|
-
class Index
|
6
|
-
attr_accessor :name, :model, :sources, :delta_object
|
7
|
-
|
8
|
-
# Create a new index instance by passing in the model it is tied to, and
|
9
|
-
# a block to build it with (optional but recommended). For documentation
|
10
|
-
# on the syntax for inside the block, the Builder class is what you want.
|
11
|
-
#
|
12
|
-
# Quick Example:
|
13
|
-
#
|
14
|
-
# Index.new(User) do
|
15
|
-
# indexes login, email
|
16
|
-
#
|
17
|
-
# has created_at
|
18
|
-
#
|
19
|
-
# set_property :delta => true
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
def initialize(model, &block)
|
23
|
-
@name = self.class.name_for model
|
24
|
-
@model = model
|
25
|
-
@sources = []
|
26
|
-
@options = {}
|
27
|
-
@delta_object = nil
|
28
|
-
end
|
29
|
-
|
30
|
-
def fields
|
31
|
-
@sources.collect { |source| source.fields }.flatten
|
32
|
-
end
|
33
|
-
|
34
|
-
def attributes
|
35
|
-
@sources.collect { |source| source.attributes }.flatten
|
36
|
-
end
|
37
|
-
|
38
|
-
def core_name
|
39
|
-
"#{name}_core"
|
40
|
-
end
|
41
|
-
|
42
|
-
def delta_name
|
43
|
-
"#{name}_delta"
|
44
|
-
end
|
45
|
-
|
46
|
-
def all_names
|
47
|
-
names = [core_name]
|
48
|
-
names << delta_name if delta?
|
49
|
-
|
50
|
-
names
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.name_for(model)
|
54
|
-
model.name.underscore.tr(':/\\', '_')
|
55
|
-
end
|
56
|
-
|
57
|
-
def prefix_fields
|
58
|
-
fields.select { |field| field.prefixes }
|
59
|
-
end
|
60
|
-
|
61
|
-
def infix_fields
|
62
|
-
fields.select { |field| field.infixes }
|
63
|
-
end
|
64
|
-
|
65
|
-
def local_options
|
66
|
-
@options
|
67
|
-
end
|
68
|
-
|
69
|
-
def options
|
70
|
-
all_index_options = config.index_options.clone
|
71
|
-
@options.keys.select { |key|
|
72
|
-
ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) ||
|
73
|
-
ThinkingSphinx::Configuration::CustomOptions.include?(key.to_s)
|
74
|
-
}.each { |key| all_index_options[key.to_sym] = @options[key] }
|
75
|
-
all_index_options
|
76
|
-
end
|
77
|
-
|
78
|
-
def delta?
|
79
|
-
!@delta_object.nil?
|
80
|
-
end
|
81
|
-
|
82
|
-
def to_riddle(offset)
|
83
|
-
indexes = [to_riddle_for_core(offset)]
|
84
|
-
indexes << to_riddle_for_delta(offset) if delta?
|
85
|
-
indexes << to_riddle_for_distributed
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def adapter
|
91
|
-
@adapter ||= @model.sphinx_database_adapter
|
92
|
-
end
|
93
|
-
|
94
|
-
def utf8?
|
95
|
-
options[:charset_type] == "utf-8"
|
96
|
-
end
|
97
|
-
|
98
|
-
def sql_query_pre_for_delta
|
99
|
-
[""]
|
100
|
-
end
|
101
|
-
|
102
|
-
def config
|
103
|
-
@config ||= ThinkingSphinx::Configuration.instance
|
104
|
-
end
|
105
|
-
|
106
|
-
def to_riddle_for_core(offset)
|
107
|
-
index = Riddle::Configuration::Index.new core_name
|
108
|
-
index.path = File.join config.searchd_file_path, index.name
|
109
|
-
|
110
|
-
set_configuration_options_for_indexes index
|
111
|
-
set_field_settings_for_indexes index
|
112
|
-
|
113
|
-
sources.each_with_index do |source, i|
|
114
|
-
index.sources << source.to_riddle_for_core(offset, i)
|
115
|
-
end
|
116
|
-
|
117
|
-
index
|
118
|
-
end
|
119
|
-
|
120
|
-
def to_riddle_for_delta(offset)
|
121
|
-
index = Riddle::Configuration::Index.new delta_name
|
122
|
-
index.parent = core_name
|
123
|
-
index.path = File.join config.searchd_file_path, index.name
|
124
|
-
|
125
|
-
sources.each_with_index do |source, i|
|
126
|
-
index.sources << source.to_riddle_for_delta(offset, i)
|
127
|
-
end
|
128
|
-
|
129
|
-
index
|
130
|
-
end
|
131
|
-
|
132
|
-
def to_riddle_for_distributed
|
133
|
-
index = Riddle::Configuration::DistributedIndex.new name
|
134
|
-
index.local_indexes << core_name
|
135
|
-
index.local_indexes.unshift delta_name if delta?
|
136
|
-
index
|
137
|
-
end
|
138
|
-
|
139
|
-
def set_configuration_options_for_indexes(index)
|
140
|
-
config.index_options.each do |key, value|
|
141
|
-
method = "#{key}=".to_sym
|
142
|
-
index.send(method, value) if index.respond_to?(method)
|
143
|
-
end
|
144
|
-
|
145
|
-
options.each do |key, value|
|
146
|
-
index.send("#{key}=".to_sym, value) if ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) && !value.nil?
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def set_field_settings_for_indexes(index)
|
151
|
-
field_names = lambda { |field| field.unique_name.to_s }
|
152
|
-
|
153
|
-
index.prefix_field_names += prefix_fields.collect(&field_names)
|
154
|
-
index.infix_field_names += infix_fields.collect(&field_names)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
@@ -1,312 +0,0 @@
|
|
1
|
-
module ThinkingSphinx
|
2
|
-
class Index
|
3
|
-
# The Builder class is the core for the index definition block processing.
|
4
|
-
# There are four methods you really need to pay attention to:
|
5
|
-
# - indexes
|
6
|
-
# - has
|
7
|
-
# - where
|
8
|
-
# - set_property/set_properties
|
9
|
-
#
|
10
|
-
# The first two of these methods allow you to define what data makes up
|
11
|
-
# your indexes. #where provides a method to add manual SQL conditions, and
|
12
|
-
# set_property allows you to set some settings on a per-index basis. Check
|
13
|
-
# out each method's documentation for better ideas of usage.
|
14
|
-
#
|
15
|
-
class Builder
|
16
|
-
instance_methods.grep(/^[^_]/).each { |method|
|
17
|
-
next if method.to_s == "instance_eval"
|
18
|
-
define_method(method) {
|
19
|
-
caller.grep(/irb.completion/).empty? ? method_missing(method) : super
|
20
|
-
}
|
21
|
-
}
|
22
|
-
|
23
|
-
def self.generate(model, name = nil, &block)
|
24
|
-
index = ThinkingSphinx::Index.new(model)
|
25
|
-
index.name = name unless name.nil?
|
26
|
-
|
27
|
-
Builder.new(index, &block) if block_given?
|
28
|
-
|
29
|
-
index.delta_object = ThinkingSphinx::Deltas.parse index
|
30
|
-
index
|
31
|
-
end
|
32
|
-
|
33
|
-
def initialize(index, &block)
|
34
|
-
@index = index
|
35
|
-
@explicit_source = false
|
36
|
-
|
37
|
-
self.instance_eval &block
|
38
|
-
|
39
|
-
if no_fields?
|
40
|
-
raise "At least one field is necessary for an index"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def define_source(&block)
|
45
|
-
if @explicit_source
|
46
|
-
@source = ThinkingSphinx::Source.new(@index)
|
47
|
-
@index.sources << @source
|
48
|
-
else
|
49
|
-
@explicit_source = true
|
50
|
-
end
|
51
|
-
|
52
|
-
self.instance_eval &block
|
53
|
-
end
|
54
|
-
|
55
|
-
# This is how you add fields - the strings Sphinx looks at - to your
|
56
|
-
# index. Technically, to use this method, you need to pass in some
|
57
|
-
# columns and options - but there's some neat method_missing stuff
|
58
|
-
# happening, so lets stick to the expected syntax within a define_index
|
59
|
-
# block.
|
60
|
-
#
|
61
|
-
# Expected options are :as, which points to a column alias in symbol
|
62
|
-
# form, and :sortable, which indicates whether you want to sort by this
|
63
|
-
# field.
|
64
|
-
#
|
65
|
-
# Adding Single-Column Fields:
|
66
|
-
#
|
67
|
-
# You can use symbols or methods - and can chain methods together to
|
68
|
-
# get access down the associations tree.
|
69
|
-
#
|
70
|
-
# indexes :id, :as => :my_id
|
71
|
-
# indexes :name, :sortable => true
|
72
|
-
# indexes first_name, last_name, :sortable => true
|
73
|
-
# indexes users.posts.content, :as => :post_content
|
74
|
-
# indexes users(:id), :as => :user_ids
|
75
|
-
#
|
76
|
-
# Keep in mind that if any keywords for Ruby methods - such as id or
|
77
|
-
# name - clash with your column names, you need to use the symbol
|
78
|
-
# version (see the first, second and last examples above).
|
79
|
-
#
|
80
|
-
# If you specify multiple columns (example #2), a field will be created
|
81
|
-
# for each. Don't use the :as option in this case. If you want to merge
|
82
|
-
# those columns together, continue reading.
|
83
|
-
#
|
84
|
-
# Adding Multi-Column Fields:
|
85
|
-
#
|
86
|
-
# indexes [first_name, last_name], :as => :name
|
87
|
-
# indexes [location, parent.location], :as => :location
|
88
|
-
#
|
89
|
-
# To combine multiple columns into a single field, you need to wrap
|
90
|
-
# them in an Array, as shown by the above examples. There's no
|
91
|
-
# limitations on whether they're symbols or methods or what level of
|
92
|
-
# associations they come from.
|
93
|
-
#
|
94
|
-
# Adding SQL Fragment Fields
|
95
|
-
#
|
96
|
-
# You can also define a field using an SQL fragment, useful for when
|
97
|
-
# you would like to index a calculated value.
|
98
|
-
#
|
99
|
-
# indexes "age < 18", :as => :minor
|
100
|
-
#
|
101
|
-
def indexes(*args)
|
102
|
-
options = args.extract_options!
|
103
|
-
args.each do |columns|
|
104
|
-
field = Field.new(source, FauxColumn.coerce(columns), options)
|
105
|
-
|
106
|
-
add_sort_attribute field, options if field.sortable
|
107
|
-
add_facet_attribute field, options if field.faceted
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# This is the method to add attributes to your index (hence why it is
|
112
|
-
# aliased as 'attribute'). The syntax is the same as #indexes, so use
|
113
|
-
# that as starting point, but keep in mind the following points.
|
114
|
-
#
|
115
|
-
# An attribute can have an alias (the :as option), but it is always
|
116
|
-
# sortable - so you don't need to explicitly request that. You _can_
|
117
|
-
# specify the data type of the attribute (the :type option), but the
|
118
|
-
# code's pretty good at figuring that out itself from peering into the
|
119
|
-
# database.
|
120
|
-
#
|
121
|
-
# Attributes are limited to the following types: integers, floats,
|
122
|
-
# datetimes (converted to timestamps), booleans, strings and MVAs
|
123
|
-
# (:multi). Don't forget that Sphinx converts string attributes to
|
124
|
-
# integers, which are useful for sorting, but that's about it.
|
125
|
-
#
|
126
|
-
# Collection of integers are known as multi-value attributes (MVAs).
|
127
|
-
# Generally these would be through a has_many relationship, like in this
|
128
|
-
# example:
|
129
|
-
#
|
130
|
-
# has posts(:id), :as => :post_ids
|
131
|
-
#
|
132
|
-
# This allows you to filter on any of the values tied to a specific
|
133
|
-
# record. Might be best to read through the Sphinx documentation to get
|
134
|
-
# a better idea of that though.
|
135
|
-
#
|
136
|
-
# Adding SQL Fragment Attributes
|
137
|
-
#
|
138
|
-
# You can also define an attribute using an SQL fragment, useful for
|
139
|
-
# when you would like to index a calculated value. Don't forget to set
|
140
|
-
# the type of the attribute though:
|
141
|
-
#
|
142
|
-
# has "age < 18", :as => :minor, :type => :boolean
|
143
|
-
#
|
144
|
-
# If you're creating attributes for latitude and longitude, don't
|
145
|
-
# forget that Sphinx expects these values to be in radians.
|
146
|
-
#
|
147
|
-
def has(*args)
|
148
|
-
options = args.extract_options!
|
149
|
-
args.each do |columns|
|
150
|
-
attribute = Attribute.new(source, FauxColumn.coerce(columns), options)
|
151
|
-
|
152
|
-
add_facet_attribute attribute, options if attribute.faceted
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def facet(*args)
|
157
|
-
options = args.extract_options!
|
158
|
-
options[:facet] = true
|
159
|
-
|
160
|
-
args.each do |columns|
|
161
|
-
attribute = Attribute.new(source, FauxColumn.coerce(columns), options)
|
162
|
-
|
163
|
-
add_facet_attribute attribute, options
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def join(*args)
|
168
|
-
args.each do |association|
|
169
|
-
Join.new(source, association)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# Use this method to add some manual SQL conditions for your index
|
174
|
-
# request. You can pass in as many strings as you like, they'll get
|
175
|
-
# joined together with ANDs later on.
|
176
|
-
#
|
177
|
-
# where "user_id = 10"
|
178
|
-
# where "parent_type = 'Article'", "created_at < NOW()"
|
179
|
-
#
|
180
|
-
def where(*args)
|
181
|
-
source.conditions += args
|
182
|
-
end
|
183
|
-
|
184
|
-
# Use this method to add some manual SQL strings to the GROUP BY
|
185
|
-
# clause. You can pass in as many strings as you'd like, they'll get
|
186
|
-
# joined together with commas later on.
|
187
|
-
#
|
188
|
-
# group_by "lat", "lng"
|
189
|
-
#
|
190
|
-
def group_by(*args)
|
191
|
-
source.groupings += args
|
192
|
-
end
|
193
|
-
|
194
|
-
# This is what to use to set properties on the index. Chief amongst
|
195
|
-
# those is the delta property - to allow automatic updates to your
|
196
|
-
# indexes as new models are added and edited - but also you can
|
197
|
-
# define search-related properties which will be the defaults for all
|
198
|
-
# searches on the model.
|
199
|
-
#
|
200
|
-
# set_property :delta => true
|
201
|
-
# set_property :field_weights => {"name" => 100}
|
202
|
-
# set_property :order => "name ASC"
|
203
|
-
# set_property :select => 'name'
|
204
|
-
#
|
205
|
-
# Also, the following two properties are particularly relevant for
|
206
|
-
# geo-location searching - latitude_attr and longitude_attr. If your
|
207
|
-
# attributes for these two values are named something other than
|
208
|
-
# lat/latitude or lon/long/longitude, you can dictate what they are
|
209
|
-
# when defining the index, so you don't need to specify them for every
|
210
|
-
# geo-related search.
|
211
|
-
#
|
212
|
-
# set_property :latitude_attr => "lt", :longitude_attr => "lg"
|
213
|
-
#
|
214
|
-
# Please don't forget to add a boolean field named 'delta' to your
|
215
|
-
# model's database table if enabling the delta index for it.
|
216
|
-
# Valid options for the delta property are:
|
217
|
-
#
|
218
|
-
# true
|
219
|
-
# false
|
220
|
-
# :default
|
221
|
-
# :delayed
|
222
|
-
# :datetime
|
223
|
-
#
|
224
|
-
# You can also extend ThinkingSphinx::Deltas::DefaultDelta to implement
|
225
|
-
# your own handling for delta indexing.
|
226
|
-
#
|
227
|
-
def set_property(*args)
|
228
|
-
options = args.extract_options!
|
229
|
-
options.each do |key, value|
|
230
|
-
set_single_property key, value
|
231
|
-
end
|
232
|
-
|
233
|
-
set_single_property args[0], args[1] if args.length == 2
|
234
|
-
end
|
235
|
-
alias_method :set_properties, :set_property
|
236
|
-
|
237
|
-
# Handles the generation of new columns for the field and attribute
|
238
|
-
# definitions.
|
239
|
-
#
|
240
|
-
def method_missing(method, *args)
|
241
|
-
FauxColumn.new(method, *args)
|
242
|
-
end
|
243
|
-
|
244
|
-
# A method to allow adding fields from associations which have names
|
245
|
-
# that clash with method names in the Builder class (ie: properties,
|
246
|
-
# fields, attributes).
|
247
|
-
#
|
248
|
-
# Example: indexes assoc(:properties).column
|
249
|
-
#
|
250
|
-
def assoc(assoc, *args)
|
251
|
-
FauxColumn.new(assoc, *args)
|
252
|
-
end
|
253
|
-
|
254
|
-
# Use this method to generate SQL for your attributes, conditions, etc.
|
255
|
-
# You can pass in as whatever ActiveRecord::Base.sanitize_sql accepts.
|
256
|
-
#
|
257
|
-
# where sanitize_sql(["active = ?", true])
|
258
|
-
# #=> WHERE active = 1
|
259
|
-
#
|
260
|
-
def sanitize_sql(*args)
|
261
|
-
@index.model.send(:sanitize_sql, *args)
|
262
|
-
end
|
263
|
-
|
264
|
-
private
|
265
|
-
|
266
|
-
def source
|
267
|
-
@source ||= begin
|
268
|
-
source = ThinkingSphinx::Source.new(@index)
|
269
|
-
@index.sources << source
|
270
|
-
source
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
def set_single_property(key, value)
|
275
|
-
source_options = ThinkingSphinx::Configuration::SourceOptions
|
276
|
-
if source_options.include?(key.to_s)
|
277
|
-
source.options.merge! key => value
|
278
|
-
else
|
279
|
-
@index.local_options.merge! key => value
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
def add_sort_attribute(field, options)
|
284
|
-
add_internal_attribute field, options, "_sort"
|
285
|
-
end
|
286
|
-
|
287
|
-
def add_facet_attribute(property, options)
|
288
|
-
add_internal_attribute property, options, "_facet", true
|
289
|
-
@index.model.sphinx_facets << property.to_facet
|
290
|
-
end
|
291
|
-
|
292
|
-
def add_internal_attribute(property, options, suffix, crc = false)
|
293
|
-
return unless ThinkingSphinx::Facet.translate?(property)
|
294
|
-
|
295
|
-
Attribute.new(source,
|
296
|
-
property.columns.collect { |col| col.clone },
|
297
|
-
options.merge(
|
298
|
-
:type => property.is_a?(Field) ? :string : options[:type],
|
299
|
-
:as => property.unique_name.to_s.concat(suffix).to_sym,
|
300
|
-
:crc => crc
|
301
|
-
).except(:facet)
|
302
|
-
)
|
303
|
-
end
|
304
|
-
|
305
|
-
def no_fields?
|
306
|
-
@index.sources.empty? || @index.sources.any? { |source|
|
307
|
-
source.fields.length == 0
|
308
|
-
}
|
309
|
-
end
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|