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', 'boolean' => 'bool'

Attributes

classes  [RW] 
types  [RW] 

Public Class methods

[Source]

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

Public Instance methods

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Validate]