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