Class Ultrasphinx::Fields
In: lib/ultrasphinx/fields.rb
Parent: Object

This is a special singleton configuration class that stores the index field configurations. Rather than using a magic hash and including relevant behavior in Ultrasphinx::Configure and Ultrasphinx::Search, we unify it here.

Methods

Included Modules

Singleton Associations

Constants

TYPE_MAP = { 'string' => 'text', 'text' => 'text', 'integer' => 'integer', 'date' => 'date', 'datetime' => 'date', 'timestamp' => 'date', 'float' => 'float', 'decimal' => 'integer', # this ain't right, but float doesn't work. 'boolean' => 'bool'

Attributes

classes  [RW] 
types  [RW] 

Public Class methods

[Source]

    # File lib/ultrasphinx/fields.rb, line 28
28:     def initialize
29:       @types = {}
30:       @classes = Hash.new([])
31:       @groups = []
32:     end

Public Instance methods

[Source]

    # File lib/ultrasphinx/fields.rb, line 73
73:     def cast(source_string, field)
74:       if types[field] == "date"
75:         "UNIX_TIMESTAMP(#{source_string})"
76:       elsif types[field] == "integer"
77:         source_string # "CAST(#{source_string} AS UNSIGNED)"
78:       else
79:         source_string              
80:       end + " AS #{field}"
81:     end

[Source]

     # File lib/ultrasphinx/fields.rb, line 100
100:     def configure(configuration)
101: 
102:       configuration.each do |model, options|        
103: 
104:         klass = model.constantize        
105:         save_and_verify_type('class_id', 'integer', nil, klass)
106:         save_and_verify_type('class', 'string', nil, klass)
107:                 
108:         begin
109:         
110:           # Fields are from the model
111:           options['fields'] = options['fields'].to_a.map do |entry|
112:             extract_table_alias!(entry, klass)
113:             extract_field_alias!(entry, klass)
114:             
115:             unless klass.columns_hash[entry['field']]
116:               # XXX I think this is here for migrations
117:               Ultrasphinx.say "warning: field #{entry['field']} is not present in #{model}"
118:             else
119:               save_and_verify_type(entry['as'], klass.columns_hash[entry['field']].type, nil, klass)
120:               install_duplicate_fields!(entry, klass)
121:             end            
122:           end  
123:           
124:           # Joins are whatever they are in the target       
125:           options['include'].to_a.each do |entry|
126:             extract_table_alias!(entry, klass)
127:             extract_field_alias!(entry, klass)
128:             
129:             association_model = get_association_model(klass, entry)
130:             
131:             save_and_verify_type(entry['as'] || entry['field'], association_model.columns_hash[entry['field']].type, nil, klass)
132:             install_duplicate_fields!(entry, klass)
133:           end  
134:           
135:           # Regular concats are CHAR, group_concats are BLOB and need to be cast to CHAR
136:           options['concatenate'].to_a.each do |entry|
137:             extract_table_alias!(entry, klass)
138:             save_and_verify_type(entry['as'], 'text', nil, klass) 
139:             install_duplicate_fields!(entry, klass)
140:           end          
141:           
142:         rescue ActiveRecord::StatementInvalid
143:           Ultrasphinx.say "warning: model #{model} does not exist in the database yet"
144:         end  
145:       end
146:       
147:       self
148:     end

[Source]

     # File lib/ultrasphinx/fields.rb, line 171
171:     def extract_field_alias!(entry, klass)
172:       unless entry['as']    
173:         entry['as'] = entry['field'] 
174:       end
175:     end

[Source]

     # File lib/ultrasphinx/fields.rb, line 178
178:     def extract_table_alias!(entry, klass)
179:       unless entry['table_alias']
180:         entry['table_alias'] = if entry['field'] and entry['field'].include? "." and entry['association_sql']
181:           # This field is referenced by a table alias in association_sql
182:           table_alias, entry['field'] = entry['field'].split(".")
183:           table_alias
184:         elsif get_association(klass, entry)
185:           # Refers to the association
186:           get_association(klass, entry).name
187:         elsif entry['association_sql']
188:           # Refers to the association_sql class's table
189:           entry['class_name'].constantize.table_name
190:         else
191:           # Refers to this class
192:           klass.table_name
193:         end
194:       end
195:     end

[Source]

    # File lib/ultrasphinx/fields.rb, line 35
35:     def groups
36:       @groups.compact.sort_by do |string| 
37:         string[/= (.*)/, 1]
38:       end
39:     end

[Source]

     # File lib/ultrasphinx/fields.rb, line 151
151:     def install_duplicate_fields!(entry, klass)
152:       if entry['facet']
153:         # Source must be a string
154:         save_and_verify_type(entry['as'], 'text', nil, klass, 
155:           "#{klass}##{entry['as']}: 'facet' option is only valid for text fields; numeric fields are enabled by default")
156:         # Install facet column                
157:         save_and_verify_type("#{entry['as']}_facet", 'integer', nil, klass)
158:       end
159: 
160:       if entry['sortable']
161:         # Source must be a string
162:         save_and_verify_type(entry['as'], 'text', nil, klass, 
163:           "#{klass}##{entry['as']}: 'sortable' option is only valid for text columns; numeric fields are enabled by default")
164:         # Install sortable column        
165:         save_and_verify_type("#{entry['as']}_sortable", 'text', true, klass)      
166:       end
167:       entry
168:     end

[Source]

    # File lib/ultrasphinx/fields.rb, line 84
84:     def null(field)      
85:       case types[field]
86:         when 'text'
87:           "''"
88:         when 'integer', 'float', 'bool'
89:           "0"
90:         when 'date'
91:           "18000" # Midnight on 1/1/1970
92:         when nil
93:           raise "Field #{field} is missing"
94:         else
95:           raise "Field #{field} does not have a valid type #{types[field]}."
96:       end + " AS #{field}"
97:     end

[Source]

    # File lib/ultrasphinx/fields.rb, line 42
42:     def save_and_verify_type(field, new_type, string_sortable, klass, msg = nil)
43:       # Smoosh fields together based on their name in the Sphinx query schema
44:       field, new_type = field.to_s, TYPE_MAP[new_type.to_s]
45: 
46:       if types[field]
47:         # Existing field name; verify its type
48:         msg ||= "Column type mismatch for #{field.inspect}; was already #{types[field].inspect}, but is now #{new_type.inspect}."
49:         raise ConfigurationError, msg unless types[field] == new_type
50:         classes[field] = (classes[field] + [klass]).uniq
51: 
52:       else
53:         # New field      
54:         types[field] = new_type
55:         classes[field] = [klass]
56: 
57:         @groups << case new_type
58:           when 'integer'
59:             "sql_attr_uint = #{field}"
60:           when 'float'
61:             "sql_attr_float = #{field}"
62:           when 'bool'
63:             "sql_attr_bool = #{field}"
64:           when 'date'
65:             "sql_attr_timestamp = #{field}"
66:           when 'text' 
67:             "sql_attr_str2ordinal = #{field}" if string_sortable
68:         end
69:       end
70:     end

[Validate]