thinking-sphinx 1.4.6 → 1.4.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +6 -1
- data/features/searching_by_model.feature +24 -30
- data/features/thinking_sphinx/db/.gitignore +1 -0
- data/features/thinking_sphinx/db/fixtures/post_keywords.txt +1 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +26 -26
- data/lib/thinking_sphinx.rb +17 -26
- data/lib/thinking_sphinx/active_record.rb +69 -74
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +11 -10
- data/lib/thinking_sphinx/active_record/has_many_association.rb +2 -1
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +11 -11
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +34 -20
- data/lib/thinking_sphinx/association.rb +12 -7
- data/lib/thinking_sphinx/attribute.rb +64 -61
- data/lib/thinking_sphinx/configuration.rb +32 -36
- data/lib/thinking_sphinx/context.rb +3 -2
- data/lib/thinking_sphinx/deploy/capistrano.rb +7 -9
- data/lib/thinking_sphinx/search.rb +201 -178
- data/lib/thinking_sphinx/source/sql.rb +1 -1
- data/lib/thinking_sphinx/tasks.rb +21 -19
- data/lib/thinking_sphinx/version.rb +3 -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 +57 -0
- data/spec/sphinx_helper.rb +61 -0
- data/spec/thinking_sphinx/active_record/delta_spec.rb +24 -24
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +22 -0
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +25 -25
- data/spec/thinking_sphinx/active_record_spec.rb +110 -109
- data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +38 -38
- data/spec/thinking_sphinx/association_spec.rb +20 -2
- 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 +50 -98
- data/VERSION +0 -1
- data/tasks/distribution.rb +0 -34
- data/tasks/testing.rb +0 -80
@@ -3,12 +3,12 @@ module ThinkingSphinx
|
|
3
3
|
def initialize(model)
|
4
4
|
@model = model
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
def setup
|
8
8
|
# Deliberately blank - subclasses should do something though. Well, if
|
9
9
|
# they need to.
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def self.detect(model)
|
13
13
|
adapter = adapter_for_model model
|
14
14
|
case adapter
|
@@ -22,7 +22,7 @@ module ThinkingSphinx
|
|
22
22
|
raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{adapter}"
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def self.adapter_for_model(model)
|
27
27
|
case ThinkingSphinx.database_adapter
|
28
28
|
when String
|
@@ -35,7 +35,7 @@ module ThinkingSphinx
|
|
35
35
|
ThinkingSphinx.database_adapter
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def self.standard_adapter_for_model(model)
|
40
40
|
case model.connection.class.name
|
41
41
|
when "ActiveRecord::ConnectionAdapters::MysqlAdapter",
|
@@ -52,34 +52,34 @@ module ThinkingSphinx
|
|
52
52
|
when "jdbcpostgresql"
|
53
53
|
:postgresql
|
54
54
|
else
|
55
|
-
model.connection.config[:adapter]
|
55
|
+
model.connection.config[:adapter].to_sym
|
56
56
|
end
|
57
57
|
else
|
58
58
|
model.connection.class.name
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
def quote_with_table(column)
|
63
63
|
"#{@model.quoted_table_name}.#{@model.connection.quote_column_name(column)}"
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
def bigint_pattern
|
67
67
|
/bigint/i
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
def downcase(clause)
|
71
71
|
"LOWER(#{clause})"
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
def case(expression, pairs, default)
|
75
75
|
"CASE #{expression} " +
|
76
76
|
pairs.keys.inject('') { |string, key|
|
77
77
|
string + "WHEN '#{key}' THEN #{pairs[key]} "
|
78
78
|
} + "ELSE #{default} END"
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
protected
|
82
|
-
|
82
|
+
|
83
83
|
def connection
|
84
84
|
@connection ||= @model.connection
|
85
85
|
end
|
@@ -4,11 +4,11 @@ module ThinkingSphinx
|
|
4
4
|
create_array_accum_function
|
5
5
|
create_crc32_function
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def sphinx_identifier
|
9
9
|
"pgsql"
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def concatenate(clause, separator = ' ')
|
13
13
|
if clause[/^COALESCE/]
|
14
14
|
clause.split('), ').join(") || '#{separator}' || ")
|
@@ -18,27 +18,31 @@ module ThinkingSphinx
|
|
18
18
|
}.join(" || '#{separator}' || ")
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def group_concatenate(clause, separator = ' ')
|
23
23
|
"array_to_string(array_accum(COALESCE(#{clause}, '0')), '#{separator}')"
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def cast_to_string(clause)
|
27
27
|
clause
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def cast_to_datetime(clause)
|
31
|
-
|
31
|
+
if ThinkingSphinx::Configuration.instance.use_64_bit
|
32
|
+
"cast(extract(epoch from #{clause}) as bigint)"
|
33
|
+
else
|
34
|
+
"cast(extract(epoch from #{clause}) as int)"
|
35
|
+
end
|
32
36
|
end
|
33
|
-
|
37
|
+
|
34
38
|
def cast_to_unsigned(clause)
|
35
39
|
clause
|
36
40
|
end
|
37
|
-
|
41
|
+
|
38
42
|
def cast_to_int(clause)
|
39
43
|
"#{clause}::INT8"
|
40
44
|
end
|
41
|
-
|
45
|
+
|
42
46
|
def convert_nulls(clause, default = '')
|
43
47
|
default = case default
|
44
48
|
when String
|
@@ -50,34 +54,44 @@ module ThinkingSphinx
|
|
50
54
|
else
|
51
55
|
default
|
52
56
|
end
|
53
|
-
|
57
|
+
|
54
58
|
"COALESCE(#{clause}, #{default})"
|
55
59
|
end
|
56
|
-
|
60
|
+
|
57
61
|
def boolean(value)
|
58
62
|
value ? 'TRUE' : 'FALSE'
|
59
63
|
end
|
60
|
-
|
64
|
+
|
61
65
|
def crc(clause, blank_to_null = false)
|
62
66
|
clause = "NULLIF(#{clause},'')" if blank_to_null
|
63
67
|
"crc32(#{clause})"
|
64
68
|
end
|
65
|
-
|
69
|
+
|
66
70
|
def utf8_query_pre
|
67
71
|
nil
|
68
72
|
end
|
69
|
-
|
73
|
+
|
70
74
|
def time_difference(diff)
|
71
75
|
"current_timestamp - interval '#{diff} seconds'"
|
72
76
|
end
|
73
|
-
|
77
|
+
|
74
78
|
def utc_query_pre
|
75
79
|
"SET TIME ZONE 'UTC'"
|
76
80
|
end
|
77
|
-
|
81
|
+
|
78
82
|
private
|
79
|
-
|
83
|
+
|
80
84
|
def execute(command, output_error = false)
|
85
|
+
if RUBY_PLATFORM == 'java'
|
86
|
+
connection.transaction do
|
87
|
+
execute_command command, output_error
|
88
|
+
end
|
89
|
+
else
|
90
|
+
execute_command command, output_error
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def execute_command(command, output_error = false)
|
81
95
|
connection.execute "begin"
|
82
96
|
connection.execute "savepoint ts"
|
83
97
|
begin
|
@@ -89,7 +103,7 @@ module ThinkingSphinx
|
|
89
103
|
connection.execute "release savepoint ts"
|
90
104
|
connection.execute "commit"
|
91
105
|
end
|
92
|
-
|
106
|
+
|
93
107
|
def create_array_accum_function
|
94
108
|
if connection.raw_connection.respond_to?(:server_version) && connection.raw_connection.server_version > 80200
|
95
109
|
execute <<-SQL
|
@@ -112,7 +126,7 @@ module ThinkingSphinx
|
|
112
126
|
SQL
|
113
127
|
end
|
114
128
|
end
|
115
|
-
|
129
|
+
|
116
130
|
def create_crc32_function
|
117
131
|
execute "CREATE LANGUAGE 'plpgsql';"
|
118
132
|
function = <<-SQL
|
@@ -127,7 +141,7 @@ module ThinkingSphinx
|
|
127
141
|
IF COALESCE(word, '') = '' THEN
|
128
142
|
return 0;
|
129
143
|
END IF;
|
130
|
-
|
144
|
+
|
131
145
|
i = 0;
|
132
146
|
tmp = 4294967295;
|
133
147
|
byte_length = bit_length(word) / 8;
|
@@ -45,13 +45,8 @@ module ThinkingSphinx
|
|
45
45
|
|
46
46
|
# association is polymorphic - create associations for each
|
47
47
|
# non-polymorphic reflection.
|
48
|
-
polymorphic_classes(ref).collect { |
|
49
|
-
Association.new parent,
|
50
|
-
ref.macro,
|
51
|
-
"#{ref.name}_#{klass.name}".to_sym,
|
52
|
-
casted_options(klass, ref),
|
53
|
-
ref.active_record
|
54
|
-
)
|
48
|
+
polymorphic_classes(ref).collect { |poly_class|
|
49
|
+
Association.new parent, depolymorphic_reflection(ref, klass, poly_class)
|
55
50
|
}
|
56
51
|
end
|
57
52
|
|
@@ -119,6 +114,16 @@ module ThinkingSphinx
|
|
119
114
|
|
120
115
|
private
|
121
116
|
|
117
|
+
def self.depolymorphic_reflection(reflection, source_class, poly_class)
|
118
|
+
name = "#{reflection.name}_#{poly_class.name}".to_sym
|
119
|
+
|
120
|
+
source_class.reflect_on_association(name) ||
|
121
|
+
::ActiveRecord::Reflection::AssociationReflection.new(
|
122
|
+
reflection.macro, name, casted_options(poly_class, reflection),
|
123
|
+
reflection.active_record
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
122
127
|
# Returns all the objects that could be currently instantiated from a
|
123
128
|
# polymorphic association. This is pretty damn fast if there's an index on
|
124
129
|
# the foreign type column - but if there isn't, it can take a while if you
|
@@ -7,10 +7,10 @@ module ThinkingSphinx
|
|
7
7
|
# One key thing to remember - if you're using the attribute manually to
|
8
8
|
# generate SQL statements, you'll need to set the base model, and all the
|
9
9
|
# associations. Which can get messy. Use Index.link!, it really helps.
|
10
|
-
#
|
10
|
+
#
|
11
11
|
class Attribute < ThinkingSphinx::Property
|
12
12
|
attr_accessor :query_source
|
13
|
-
|
13
|
+
|
14
14
|
SphinxTypeMappings = {
|
15
15
|
:multi => :sql_attr_multi,
|
16
16
|
:datetime => :sql_attr_timestamp,
|
@@ -21,11 +21,11 @@ module ThinkingSphinx
|
|
21
21
|
:bigint => :sql_attr_bigint,
|
22
22
|
:wordcount => :sql_attr_str2wordcount
|
23
23
|
}
|
24
|
-
|
24
|
+
|
25
25
|
if Riddle.loaded_version.to_i > 1
|
26
26
|
SphinxTypeMappings[:string] = :sql_attr_string
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# To create a new attribute, you'll need to pass in either a single Column
|
30
30
|
# or an array of them, and some (optional) options.
|
31
31
|
#
|
@@ -37,13 +37,13 @@ module ThinkingSphinx
|
|
37
37
|
# Alias is only required in three circumstances: when there's
|
38
38
|
# another attribute or field with the same name, when the column name is
|
39
39
|
# 'id', or when there's more than one column.
|
40
|
-
#
|
40
|
+
#
|
41
41
|
# Type is not required, unless you want to force a column to be a certain
|
42
42
|
# type (but keep in mind the value will not be CASTed in the SQL
|
43
43
|
# statements). The only time you really need to use this is when the type
|
44
44
|
# can't be figured out by the column - ie: when not actually using a
|
45
45
|
# database column as your source.
|
46
|
-
#
|
46
|
+
#
|
47
47
|
# Source is only used for multi-value attributes (MVA). By default this will
|
48
48
|
# use a left-join and a group_concat to obtain the values. For better performance
|
49
49
|
# during indexing it can be beneficial to let Sphinx use a separate query to retrieve
|
@@ -81,33 +81,34 @@ module ThinkingSphinx
|
|
81
81
|
#
|
82
82
|
# If you're creating attributes for latitude and longitude, don't forget
|
83
83
|
# that Sphinx expects these values to be in radians.
|
84
|
-
#
|
84
|
+
#
|
85
85
|
def initialize(source, columns, options = {})
|
86
86
|
super
|
87
|
-
|
87
|
+
|
88
88
|
@type = options[:type]
|
89
89
|
@query_source = options[:source]
|
90
90
|
@crc = options[:crc]
|
91
|
-
|
91
|
+
@all_ints = options[:all_ints]
|
92
|
+
|
92
93
|
@type ||= :multi unless @query_source.nil?
|
93
94
|
if @type == :string && @crc
|
94
95
|
@type = is_many? ? :multi : :integer
|
95
96
|
end
|
96
|
-
|
97
|
+
|
97
98
|
source.attributes << self
|
98
99
|
end
|
99
|
-
|
100
|
+
|
100
101
|
# Get the part of the SELECT clause related to this attribute. Don't forget
|
101
102
|
# to set your model and associations first though.
|
102
103
|
#
|
103
104
|
# This will concatenate strings and arrays of integers, and convert
|
104
105
|
# datetimes to timestamps, as needed.
|
105
|
-
#
|
106
|
+
#
|
106
107
|
def to_select_sql
|
107
108
|
return nil unless include_as_association? && available?
|
108
|
-
|
109
|
+
|
109
110
|
separator = all_ints? || all_datetimes? || @crc ? ',' : ' '
|
110
|
-
|
111
|
+
|
111
112
|
clause = columns_with_prefixes.collect { |column|
|
112
113
|
case type
|
113
114
|
when :string
|
@@ -122,28 +123,28 @@ module ThinkingSphinx
|
|
122
123
|
column
|
123
124
|
end
|
124
125
|
}.join(', ')
|
125
|
-
|
126
|
+
|
126
127
|
clause = adapter.crc(clause) if @crc
|
127
128
|
clause = adapter.concatenate(clause, separator) if concat_ws?
|
128
129
|
clause = adapter.group_concatenate(clause, separator) if is_many?
|
129
130
|
clause = adapter.downcase(clause) if insensitive?
|
130
|
-
|
131
|
+
|
131
132
|
"#{clause} AS #{quote_column(unique_name)}"
|
132
133
|
end
|
133
|
-
|
134
|
+
|
134
135
|
def type_to_config
|
135
136
|
SphinxTypeMappings[type]
|
136
137
|
end
|
137
|
-
|
138
|
+
|
138
139
|
def include_as_association?
|
139
140
|
! (type == :multi && (query_source == :query || query_source == :ranged_query))
|
140
141
|
end
|
141
|
-
|
142
|
+
|
142
143
|
# Returns the configuration value that should be used for
|
143
144
|
# the attribute.
|
144
145
|
# Special case is the multi-valued attribute that needs some
|
145
|
-
# extra configuration.
|
146
|
-
#
|
146
|
+
# extra configuration.
|
147
|
+
#
|
147
148
|
def config_value(offset = nil, delta = false)
|
148
149
|
if type == :multi
|
149
150
|
multi_config = include_as_association? ? "field" :
|
@@ -153,12 +154,12 @@ module ThinkingSphinx
|
|
153
154
|
unique_name
|
154
155
|
end
|
155
156
|
end
|
156
|
-
|
157
|
+
|
157
158
|
# Returns the type of the column. If that's not already set, it returns
|
158
159
|
# :multi if there's the possibility of more than one value, :string if
|
159
160
|
# there's more than one association, otherwise it figures out what the
|
160
161
|
# actual column's datatype is and returns that.
|
161
|
-
#
|
162
|
+
#
|
162
163
|
def type
|
163
164
|
@type ||= begin
|
164
165
|
base_type = case
|
@@ -169,21 +170,23 @@ module ThinkingSphinx
|
|
169
170
|
else
|
170
171
|
translated_type_from_database
|
171
172
|
end
|
172
|
-
|
173
|
+
|
173
174
|
if base_type == :string && @crc
|
174
175
|
base_type = :integer
|
175
176
|
else
|
176
177
|
@crc = false unless base_type == :multi && is_many_strings? && @crc
|
177
178
|
end
|
178
|
-
|
179
|
+
|
179
180
|
base_type
|
180
181
|
end
|
181
182
|
end
|
182
|
-
|
183
|
+
|
183
184
|
def updatable?
|
184
|
-
[:integer, :datetime, :boolean].include?(type) &&
|
185
|
+
[:integer, :datetime, :boolean].include?(type) &&
|
186
|
+
unique_name != :sphinx_internal_id &&
|
187
|
+
!is_string?
|
185
188
|
end
|
186
|
-
|
189
|
+
|
187
190
|
def live_value(instance)
|
188
191
|
object = instance
|
189
192
|
column = @columns.first
|
@@ -191,29 +194,29 @@ module ThinkingSphinx
|
|
191
194
|
object = object.send(method)
|
192
195
|
return sphinx_value(nil) if object.nil?
|
193
196
|
}
|
194
|
-
|
197
|
+
|
195
198
|
sphinx_value object.send(column.__name)
|
196
199
|
end
|
197
|
-
|
200
|
+
|
198
201
|
def all_ints?
|
199
|
-
all_of_type?(:integer)
|
202
|
+
@all_ints || all_of_type?(:integer)
|
200
203
|
end
|
201
|
-
|
204
|
+
|
202
205
|
def all_datetimes?
|
203
206
|
all_of_type?(:datetime, :date, :timestamp)
|
204
207
|
end
|
205
|
-
|
208
|
+
|
206
209
|
def all_strings?
|
207
210
|
all_of_type?(:string, :text)
|
208
211
|
end
|
209
|
-
|
212
|
+
|
210
213
|
private
|
211
|
-
|
214
|
+
|
212
215
|
def source_value(offset, delta)
|
213
216
|
if is_string?
|
214
217
|
return "#{query_source.to_s.dasherize}; #{columns.first.__name}"
|
215
218
|
end
|
216
|
-
|
219
|
+
|
217
220
|
query = query(offset)
|
218
221
|
|
219
222
|
if query_source == :ranged_query
|
@@ -225,12 +228,12 @@ module ThinkingSphinx
|
|
225
228
|
"query; #{query}"
|
226
229
|
end
|
227
230
|
end
|
228
|
-
|
231
|
+
|
229
232
|
def query(offset)
|
230
233
|
base_assoc = base_association_for_mva
|
231
234
|
end_assoc = end_association_for_mva
|
232
235
|
raise "Could not determine SQL for MVA" if base_assoc.nil?
|
233
|
-
|
236
|
+
|
234
237
|
<<-SQL
|
235
238
|
SELECT #{foreign_key_for_mva base_assoc}
|
236
239
|
#{ThinkingSphinx.unique_id_expression(adapter, offset)} AS #{quote_column('id')},
|
@@ -238,12 +241,12 @@ SELECT #{foreign_key_for_mva base_assoc}
|
|
238
241
|
FROM #{quote_table_name base_assoc.table} #{association_joins}
|
239
242
|
SQL
|
240
243
|
end
|
241
|
-
|
244
|
+
|
242
245
|
def query_clause
|
243
246
|
foreign_key = foreign_key_for_mva base_association_for_mva
|
244
247
|
"WHERE #{foreign_key} >= $start AND #{foreign_key} <= $end"
|
245
248
|
end
|
246
|
-
|
249
|
+
|
247
250
|
def query_delta
|
248
251
|
foreign_key = foreign_key_for_mva base_association_for_mva
|
249
252
|
<<-SQL
|
@@ -252,40 +255,40 @@ FROM #{model.quoted_table_name}
|
|
252
255
|
WHERE #{@source.index.delta_object.clause(model, true)})
|
253
256
|
SQL
|
254
257
|
end
|
255
|
-
|
258
|
+
|
256
259
|
def range_query
|
257
260
|
assoc = base_association_for_mva
|
258
261
|
foreign_key = foreign_key_for_mva assoc
|
259
262
|
"SELECT MIN(#{foreign_key}), MAX(#{foreign_key}) FROM #{quote_table_name assoc.table}"
|
260
263
|
end
|
261
|
-
|
264
|
+
|
262
265
|
def primary_key_for_mva(assoc)
|
263
266
|
quote_with_table(
|
264
267
|
assoc.table, assoc.primary_key_from_reflection || columns.first.__name
|
265
268
|
)
|
266
269
|
end
|
267
|
-
|
270
|
+
|
268
271
|
def foreign_key_for_mva(assoc)
|
269
272
|
quote_with_table assoc.table, assoc.reflection.primary_key_name
|
270
273
|
end
|
271
|
-
|
274
|
+
|
272
275
|
def end_association_for_mva
|
273
276
|
@association_for_mva ||= associations[columns.first].detect { |assoc|
|
274
277
|
assoc.has_column?(columns.first.__name)
|
275
278
|
}
|
276
279
|
end
|
277
|
-
|
280
|
+
|
278
281
|
def base_association_for_mva
|
279
282
|
@first_association_for_mva ||= begin
|
280
283
|
assoc = end_association_for_mva
|
281
284
|
while !assoc.parent.nil?
|
282
285
|
assoc = assoc.parent
|
283
286
|
end
|
284
|
-
|
287
|
+
|
285
288
|
assoc
|
286
289
|
end
|
287
290
|
end
|
288
|
-
|
291
|
+
|
289
292
|
def association_joins
|
290
293
|
joins = []
|
291
294
|
assoc = end_association_for_mva
|
@@ -293,22 +296,22 @@ WHERE #{@source.index.delta_object.clause(model, true)})
|
|
293
296
|
joins << assoc.to_sql
|
294
297
|
assoc = assoc.parent
|
295
298
|
end
|
296
|
-
|
299
|
+
|
297
300
|
joins.join(' ')
|
298
301
|
end
|
299
|
-
|
302
|
+
|
300
303
|
def is_many_ints?
|
301
304
|
concat_ws? && all_ints?
|
302
305
|
end
|
303
|
-
|
306
|
+
|
304
307
|
def is_many_datetimes?
|
305
308
|
is_many? && all_datetimes?
|
306
309
|
end
|
307
|
-
|
310
|
+
|
308
311
|
def is_many_strings?
|
309
312
|
is_many? && all_strings?
|
310
313
|
end
|
311
|
-
|
314
|
+
|
312
315
|
def translated_type_from_database
|
313
316
|
case type_from_db = type_from_database
|
314
317
|
when :integer
|
@@ -330,16 +333,16 @@ block:
|
|
330
333
|
MESSAGE
|
331
334
|
end
|
332
335
|
end
|
333
|
-
|
336
|
+
|
334
337
|
def type_from_database
|
335
338
|
column = column_from_db
|
336
339
|
column.nil? ? nil : column.type
|
337
340
|
end
|
338
|
-
|
341
|
+
|
339
342
|
def integer_type_from_db
|
340
343
|
column = column_from_db
|
341
344
|
return nil if column.nil?
|
342
|
-
|
345
|
+
|
343
346
|
case column.sql_type
|
344
347
|
when adapter.bigint_pattern
|
345
348
|
:bigint
|
@@ -347,16 +350,16 @@ block:
|
|
347
350
|
:integer
|
348
351
|
end
|
349
352
|
end
|
350
|
-
|
353
|
+
|
351
354
|
def column_from_db
|
352
|
-
klass = @associations.values.flatten.first ?
|
355
|
+
klass = @associations.values.flatten.first ?
|
353
356
|
@associations.values.flatten.first.reflection.klass : @model
|
354
|
-
|
357
|
+
|
355
358
|
klass.columns.detect { |col|
|
356
359
|
@columns.collect { |c| c.__name.to_s }.include? col.name
|
357
360
|
}
|
358
361
|
end
|
359
|
-
|
362
|
+
|
360
363
|
def all_of_type?(*column_types)
|
361
364
|
@columns.all? { |col|
|
362
365
|
klasses = @associations[col].empty? ? [@model] :
|
@@ -367,7 +370,7 @@ block:
|
|
367
370
|
}
|
368
371
|
}
|
369
372
|
end
|
370
|
-
|
373
|
+
|
371
374
|
def sphinx_value(value)
|
372
375
|
case value
|
373
376
|
when TrueClass
|
@@ -384,7 +387,7 @@ block:
|
|
384
387
|
value
|
385
388
|
end
|
386
389
|
end
|
387
|
-
|
390
|
+
|
388
391
|
def insensitive?
|
389
392
|
@sortable == :insensitive
|
390
393
|
end
|