class FastAPI::SQL
Public Class Methods
new(filters, offset, count, klazz, whitelist, safe = false)
click to toggle source
# File lib/fastapi/sql.rb, line 9 def initialize(filters, offset, count, klazz, whitelist, safe = false) results = filter_fields(klazz, whitelist) models, belongs, has_many, fields = results.values_at(:models, :belongs, :has_many, :fields) model_name = klazz.to_s.tableize.singularize table_name = klazz.to_s.tableize # Base fields field_list = generate_field_list(klazz, fields, table_name) # Belongs fields joins = parse_belongs(belongs, field_list, table_name) # Many fields (1 to many) parse_manys(has_many, filters, field_list, model_name, table_name) filter_string = filters[:main].size > 0 ? "WHERE #{filters[:main].join(' AND ')}" : nil order_string = filters[:main_order] ? "ORDER BY #{filters[:main_order]}" : nil @sql = { query: [ "SELECT #{field_list.join(', ')}", "FROM #{table_name}", joins.join(' '), filter_string, order_string, "LIMIT #{count}", "OFFSET #{offset}" ].compact.join(' '), count_query: [ "SELECT COUNT(id) FROM #{table_name}", filter_string ].compact.join(' '), models: models } end
Private Instance Methods
constantize_model(class_name, field)
click to toggle source
# File lib/fastapi/sql.rb, line 162 def constantize_model(class_name, field) (class_name ? class_name : field.to_s.classify).constantize end
filter_fields(klazz, whitelist)
click to toggle source
# File lib/fastapi/sql.rb, line 48 def filter_fields(klazz, whitelist) skeleton = { models: {}, belongs: [], has_many: [], fields: [] } (klazz.fastapi_fields + whitelist).each_with_object(skeleton) do |field, results| if klazz.reflect_on_all_associations(:belongs_to).map(&:name).include?(field) class_name = klazz.reflect_on_association(field).options[:class_name] model = constantize_model(class_name, field) results[:models][field] = model results[:belongs] << { model: model, alias: field, type: :belongs_to } elsif klazz.reflect_on_all_associations(:has_one).map(&:name).include?(field) class_name = klazz.reflect_on_association(field).options[:class_name] model = constantize_model(class_name, field) results[:models][field] = model results[:belongs] << { model: model, alias: field, type: :has_one } elsif klazz.reflect_on_all_associations(:has_many).map(&:name).include?(field) model = field.to_s.singularize.classify.constantize results[:models][field] = model results[:has_many] << model elsif klazz.column_names.include?(field.to_s) results[:fields] << field end end end
generate_field_list(klazz, fields, table)
click to toggle source
# File lib/fastapi/sql.rb, line 82 def generate_field_list(klazz, fields, table) fields.each_with_object([]) do |field, list| if klazz.columns_hash[field.to_s].respond_to?(:array) && klazz.columns_hash[field.to_s].array list << "ARRAY_TO_JSON(#{table}.#{field}) AS #{field}" else list << "#{table}.#{field} AS #{field}" end end end
parse_belongs(belongs, field_list, model_table_name)
click to toggle source
# File lib/fastapi/sql.rb, line 92 def parse_belongs(belongs, field_list, model_table_name) belongs.each_with_object([]) do |model_data, join_list| table_name = model_data[:model].to_s.tableize table_alias = model_data[:alias].to_s.pluralize field_name = model_data[:alias].to_s singular_table_name = model_table_name.singularize model_data[:model].fastapi_fields_sub.each do |field| if model_data[:model].columns_hash[field.to_s].respond_to?(:array) && model_data[:model].columns_hash[field.to_s].array field_list << "ARRAY_TO_JSON(#{table_alias}.#{field}) AS #{field_name}__#{field}" else field_list << "#{table_alias}.#{field} AS #{field_name}__#{field}" end end # fields if model_data[:type] == :belongs_to # joins join_list << "LEFT JOIN #{table_name} AS #{table_alias} " \ "ON #{table_alias}.id = #{model_table_name}.#{field_name}_id" elsif model_data[:type] == :has_one join_list << "LEFT JOIN #{table_name} AS #{table_alias} " \ "ON #{table_alias}.#{singular_table_name}_id = #{model_table_name}.id" end end end
parse_manys(has_many, filters, field_list, model_name, table_name)
click to toggle source
# File lib/fastapi/sql.rb, line 121 def parse_manys(has_many, filters, field_list, model_name, table_name) has_many.each do |model| model_string_table = model.to_s.tableize model_symbol = model_string_table.to_sym model_fields = model.fastapi_fields_sub.each_with_object([]) do |field, m_fields| m_fields << "__#{model_string_table}.#{field}" end if filters[:has_many].has_key?(model_symbol) if not filters[:has_many][model_symbol].blank? has_many_filters = "AND #{filters[:has_many][model_symbol].join(' AND ')}" else has_many_filters = nil end if not filters[:has_many_order][model_symbol].blank? has_many_order = "ORDER BY #{filters[:has_many_order][model_symbol]}" else has_many_order = nil end end field_list << [ "ARRAY_TO_JSON(ARRAY(SELECT ROW(#{model_fields.join(', ')})", "FROM #{model_string_table}", "AS __#{model_string_table}", "WHERE __#{model_string_table}.#{model_name}_id IS NOT NULL", "AND __#{model_string_table}.#{model_name}_id", "= #{table_name}.id", has_many_filters, has_many_order, ")) AS __many__#{model_string_table}" ].compact.join(' ') end end