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 271 271: def construct_join_sql(key_relation, num ) 272: join_sql = "" 273: connection = klass.connection 274: key = key_relation.to_s.singularize.to_sym 275: main = definition.klass.to_s.gsub(/.*::/,'').underscore.to_sym 276: 277: key_table = klass.reflections[key].table_name 278: key_table_pk = klass.reflections[key].klass.primary_key 279: 280: value_table = klass.table_name.to_s 281: value_table_fk_key = klass.reflections[key].association_foreign_key 282: 283: if klass.reflections[main] 284: main_table = definition.klass.table_name 285: main_table_pk = klass.reflections[main].klass.primary_key 286: value_table_fk_main = klass.reflections[main].association_foreign_key 287: 288: 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})" 289: value_table = " #{value_table}_#{num}" 290: end 291: 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}) " 292: 293: return join_sql 294: 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 305 305: def construct_simple_join_sql( num ) 306: connection = klass.connection 307: main = definition.klass.to_s.gsub(/.*::/,'').underscore.to_sym 308: key_value_table = klass.table_name 309: 310: main_table = definition.klass.table_name 311: main_table_pk = klass.reflections[main].klass.primary_key 312: value_table_fk_main = klass.reflections[main].options[:foreign_key] 313: value_table_fk_main ||= klass.reflections[main].association_foreign_key 314: 315: 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})" 316: return join_sql 317: end
# File lib/scoped_search/query_builder.rb, line 319 319: def to_ext_method_sql(key, operator, value, &block) 320: raise ScopedSearch::QueryNotSupported, "'#{definition.klass}' doesn't respond to '#{ext_method}'" unless definition.klass.respond_to?(ext_method) 321: conditions = definition.klass.send(ext_method.to_sym,key, operator, value) rescue {} 322: raise ScopedSearch::QueryNotSupported, "external method '#{ext_method}' should return hash" unless conditions.kind_of?(Hash) 323: sql = '' 324: conditions.map do |notification, content| 325: case notification 326: when :include then yield(:include, content) 327: when :joins then yield(:joins, content) 328: when :conditions then sql = content 329: when :parameter then content.map{|c| yield(:parameter, c)} 330: end 331: end 332: return sql 333: 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 241 241: def to_sql(operator = nil, &block) # :yields: finder_option_type, value 242: num = rand(1000000) 243: connection = klass.connection 244: if key_relation 245: yield(:joins, construct_join_sql(key_relation, num) ) 246: yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?") 247: klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name) 248: return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}" 249: elsif key_field 250: yield(:joins, construct_simple_join_sql(num)) 251: yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?") 252: klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name) 253: return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}" 254: elsif relation 255: yield(:include, relation) 256: end 257: column_name = connection.quote_table_name(klass.table_name.to_s) + "." + connection.quote_column_name(field.to_s) 258: column_name = "(#{column_name} >> #{offset*word_size} & #{2**word_size - 1})" if offset 259: column_name 260: end