| Module | ScopedSearch::QueryBuilder::Field |
| In: |
lib/scoped_search/query_builder.rb
|
This module gets included into the Field class to add SQL generation.
This method construct join statement for a key value table It assume the following table structure
+----------+ +---------+ +--------+ | main | | value | | key | | main_pk | | main_fk | | | | | | key_fk | | key_pk | +----------+ +---------+ +--------+
uniq name for the joins are needed in case that there is more than one condition on different keys in the same query.
# File lib/scoped_search/query_builder.rb, line 270
270: def construct_join_sql(key_relation, num )
271: join_sql = ""
272: connection = klass.connection
273: key = key_relation.to_s.singularize.to_sym
274: main = definition.klass.to_s.gsub(/.*::/,'').underscore.to_sym
275:
276: key_table = klass.reflections[key].table_name
277: key_table_pk = klass.reflections[key].klass.primary_key
278:
279: value_table = klass.table_name.to_s
280: value_table_fk_key = klass.reflections[key].association_foreign_key
281:
282: if klass.reflections[main]
283: main_table = definition.klass.table_name
284: main_table_pk = klass.reflections[main].klass.primary_key
285: value_table_fk_main = klass.reflections[main].association_foreign_key
286:
287: join_sql = "\n INNER JOIN #{connection.quote_table_name(value_table)} #{value_table}_#{num} ON (#{main_table}.#{main_table_pk} = #{value_table}_#{num}.#{value_table_fk_main})"
288: value_table = " #{value_table}_#{num}"
289: end
290: join_sql += "\n INNER JOIN #{connection.quote_table_name(key_table)} #{key_table}_#{num} ON (#{key_table}_#{num}.#{key_table_pk} = #{value_table}.#{value_table_fk_key}) "
291:
292: return join_sql
293: end
This method construct join statement for a key value table It assume the following table structure
+----------+ +---------+ | main | | key | | main_pk | | value | | | | main_fk | +----------+ +---------+
uniq name for the joins are needed in case that there is more than one condition on different keys in the same query.
# File lib/scoped_search/query_builder.rb, line 304
304: def construct_simple_join_sql( num )
305: connection = klass.connection
306: main = definition.klass.to_s.gsub(/.*::/,'').underscore.to_sym
307: key_value_table = klass.table_name
308:
309: main_table = definition.klass.table_name
310: main_table_pk = klass.reflections[main].klass.primary_key
311: value_table_fk_main = klass.reflections[main].options[:foreign_key]
312: value_table_fk_main ||= klass.reflections[main].association_foreign_key
313:
314: join_sql = "\n INNER JOIN #{connection.quote_table_name(key_value_table)} #{key_value_table}_#{num} ON (#{connection.quote_table_name(main_table)}.#{main_table_pk} = #{key_value_table}_#{num}.#{value_table_fk_main})"
315: return join_sql
316: end
# File lib/scoped_search/query_builder.rb, line 318
318: def to_ext_method_sql(key, operator, value, &block)
319: raise ScopedSearch::QueryNotSupported, "'#{definition.klass}' doesn't respond to '#{ext_method}'" unless definition.klass.respond_to?(ext_method)
320: conditions = definition.klass.send(ext_method.to_sym,key, operator, value) rescue {}
321: raise ScopedSearch::QueryNotSupported, "external method '#{ext_method}' should return hash" unless conditions.kind_of?(Hash)
322: sql = ''
323: conditions.map do |notification, content|
324: case notification
325: when :include then yield(:include, content)
326: when :joins then yield(:joins, content)
327: when :conditions then sql = content
328: when :parameter then content.map{|c| yield(:parameter, c)}
329: end
330: end
331: return sql
332: end
Return an SQL representation for this field. Also make sure that the relation which includes the search field is included in the SQL query.
This function may yield an :include that should be used in the ActiveRecord::Base#find call, to make sure that the field is available for the SQL query.
# File lib/scoped_search/query_builder.rb, line 240
240: def to_sql(operator = nil, &block) # :yields: finder_option_type, value
241: num = rand(1000000)
242: connection = klass.connection
243: if key_relation
244: yield(:joins, construct_join_sql(key_relation, num) )
245: yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?")
246: klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name)
247: return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}"
248: elsif key_field
249: yield(:joins, construct_simple_join_sql(num))
250: yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?")
251: klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name)
252: return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}"
253: elsif relation
254: yield(:include, relation)
255: end
256: column_name = connection.quote_table_name(klass.table_name.to_s) + "." + connection.quote_column_name(field.to_s)
257: column_name = "(#{column_name} >> #{offset*word_size} & #{2**word_size - 1})" if offset
258: column_name
259: end