| 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.
| 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' |
| classes | [RW] | |
| types | [RW] |
# File lib/ultrasphinx/fields.rb, line 28
28: def initialize
29: @types = {}
30: @classes = Hash.new([])
31: @groups = []
32: end
# 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
# 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
# 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
# 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
# File lib/ultrasphinx/fields.rb, line 35
35: def groups
36: @groups.compact.sort_by do |string|
37: string[/= (.*)/, 1]
38: end
39: end
# 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
# 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
# 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