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 259 259: def construct_join_sql(key_relation, num ) 260: join_sql = "" 261: connection = klass.connection 262: key = key_relation.to_s.singularize.to_sym 263: main = definition.klass.to_s.gsub(/.*::/,'').underscore.to_sym 264: 265: key_table = klass.reflections[key].table_name 266: key_table_pk = klass.reflections[key].klass.primary_key 267: 268: value_table = klass.table_name.to_s 269: value_table_fk_key = klass.reflections[key].association_foreign_key 270: 271: if klass.reflections[main] 272: main_table = definition.klass.table_name 273: main_table_pk = klass.reflections[main].klass.primary_key 274: value_table_fk_main = klass.reflections[main].association_foreign_key 275: 276: 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})" 277: value_table = " #{value_table}_#{num}" 278: end 279: 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}) " 280: 281: return join_sql 282: 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 293 293: def construct_simple_join_sql( num ) 294: connection = klass.connection 295: main = definition.klass.to_s.gsub(/.*::/,'').underscore.to_sym 296: key_value_table = klass.table_name 297: 298: main_table = definition.klass.table_name 299: main_table_pk = klass.reflections[main].klass.primary_key 300: value_table_fk_main = klass.reflections[main].options[:foreign_key] 301: value_table_fk_main ||= klass.reflections[main].association_foreign_key 302: 303: 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})" 304: return join_sql 305: end
# File lib/scoped_search/query_builder.rb, line 307 307: def to_ext_method_sql(key, operator, value, &block) 308: raise ScopedSearch::QueryNotSupported, "'#{definition.klass}' doesn't respond to '#{ext_method}'" unless definition.klass.respond_to?(ext_method) 309: conditions = definition.klass.send(ext_method.to_sym,key, operator, value) rescue {} 310: raise ScopedSearch::QueryNotSupported, "external method '#{ext_method}' should return hash" unless conditions.kind_of?(Hash) 311: sql = '' 312: conditions.map do |notification, content| 313: case notification 314: when :include then yield(:include, content) 315: when :joins then yield(:joins, content) 316: when :conditions then sql = content 317: when :parameter then content.map{|c| yield(:parameter, c)} 318: end 319: end 320: return sql 321: 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 229 229: def to_sql(operator = nil, &block) # :yields: finder_option_type, value 230: num = rand(1000000) 231: connection = klass.connection 232: if key_relation 233: yield(:joins, construct_join_sql(key_relation, num) ) 234: yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?") 235: klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name) 236: return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}" 237: elsif key_field 238: yield(:joins, construct_simple_join_sql(num)) 239: yield(:keycondition, "#{key_klass.table_name}_#{num}.#{connection.quote_column_name(key_field.to_s)} = ?") 240: klass_table_name = relation ? "#{klass.table_name}_#{num}" : connection.quote_table_name(klass.table_name) 241: return "#{klass_table_name}.#{connection.quote_column_name(field.to_s)}" 242: elsif relation 243: yield(:include, relation) 244: end 245: column_name = connection.quote_table_name(klass.table_name.to_s) + "." + connection.quote_column_name(field.to_s) 246: column_name = "(#{column_name} >> #{offset*word_size} & #{2**word_size - 1})" if offset 247: column_name 248: end