Closed RafaelMCarvalho closed 7 years ago
Yes it's on my list for version 2.0 which will also be JSON API compliant. I am not sure how the API for #or will look like (maybe like you suggest) but it will exploit rails 5 AR #OR method. Probably it will land around December unless you want to send a pull request :)
Great Lib! Thnx!
I've been trying to implement or-filters, here is my result so far:
In the column filters I added the or_filters
function (down below), and at each null_filters I added a call to or_filters:
module ActiveHashRelation::ColumnFilters
def filter_primary(resource, column, param)
resource = resource.where(id: param)
end
def filter_integer(resource, column, table_name, param)
if param.is_a? Array
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
return resource.where("#{table_name}.#{column} IN (#{n_param})")
elsif param.is_a? Hash
if !param[:null].nil?
return null_filters(resource, table_name, column, param)
elsif param[:or]
return or_filters(resource, table_name, column, param, __method__)
else
return apply_leq_geq_le_ge_filters(resource, table_name, column, param)
end
else
return resource.where("#{table_name}.#{column} = ?", param)
end
end
def filter_float(resource, column, table_name, param)
filter_integer(resource, column, table_name, param)
end
def filter_decimal(resource, column, table_name, param)
filter_integer(resource, column, table_name, param)
end
def filter_string(resource, column, table_name, param)
if param.is_a? Array
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
return resource.where("#{table_name}.#{column} IN (#{n_param})")
elsif param.is_a? Hash
if !param[:null].nil?
return null_filters(resource, table_name, column, param)
elsif param[:or]
return or_filters(resource, table_name, column, param, __method__)
else
return apply_like_filters(resource, table_name, column, param)
end
else
return resource.where("#{table_name}.#{column} = ?", param)
end
end
def filter_text(resource, column, param)
return filter_string(resource, column, param)
end
def filter_date(resource, column, table_name, param)
if param.is_a? Array
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
return resource.where("#{table_name}.#{column} IN (#{n_param})")
elsif param.is_a? Hash
if !param[:null].nil?
return null_filters(resource, table_name, column, param)
elsif param[:or]
return or_filters(resource, table_name, column, param, __method__)
else
return apply_leq_geq_le_ge_filters(resource, table_name, column, param)
end
else
resource = resource.where(column => param)
end
return resource
end
def filter_datetime(resource, column, table_name, param)
if param.is_a? Array
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
return resource = resource.where("#{table_name}.#{column} IN (#{n_param})")
elsif param.is_a? Hash
if !param[:null].nil?
return null_filters(resource, table_name, column, param)
elsif param[:or]
return or_filters(resource, table_name, column, param, __method__)
else
return apply_leq_geq_le_ge_filters(resource, table_name, column, param)
end
else
resource = resource.where(column => param)
end
return resource
end
def filter_boolean(resource, column, param)
b_param = ActiveRecord::Type::Boolean.new.type_cast_from_database(param)
resource = resource.where(column => b_param)
end
private
def apply_leq_geq_le_ge_filters(resource, table_name, column, param)
if !param[:leq].blank?
resource = resource.where("#{table_name}.#{column} <= ?", param[:leq])
elsif !param[:le].blank?
resource = resource.where("#{table_name}.#{column} < ?", param[:le])
end
if !param[:geq].blank?
resource = resource.where("#{table_name}.#{column} >= ?", param[:geq])
elsif !param[:ge].blank?
resource = resource.where("#{table_name}.#{column} > ?", param[:ge])
end
return resource
end
def apply_like_filters(resource, table_name, column, param)
like_method = "LIKE"
like_method = "ILIKE" if param[:with_ilike]
if !param[:starts_with].blank?
resource = resource.where("#{table_name}.#{column} #{like_method} ?", "#{param[:starts_with]}%")
end
if !param[:ends_with].blank?
resource = resource.where("#{table_name}.#{column} #{like_method} ?", "%#{param[:ends_with]}")
end
if !param[:like].blank?
resource = resource.where("#{table_name}.#{column} #{like_method} ?", "%#{param[:like]}%")
end
if !param[:eq].blank?
resource = resource.where("#{table_name}.#{column} = ?", param[:eq])
end
return resource
end
def null_filters(resource, table_name, column, param)
if param[:null] == true
resource = resource.where("#{table_name}.#{column} IS NULL")
end
if param[:null] == false
resource = resource.where("#{table_name}.#{column} IS NOT NULL")
end
return resource
end
def or_filters(resource, table_name, column, param, filter_method)
base_resource = resource # Save base, so to make each or_filter work on the same base-set
param[:or] = param[:or].map { |k, v| {k => v} } # Convert to array
param[:or].each_with_index { |p, i|
or_filter = send(filter_method, base_resource, column, table_name, p)
if i == 0
resource = or_filter # Nothing to 'or' on for the first or filter
else
resource = resource.or(or_filter)
end
}
return resource
end
end
It is to be called as suggested: apply_filters(resource, { or: { title: "Ruby", content: "Rails" })
It also works with null filters.
One thing I don't understand is why I have to overwrite the param[:or] =
in my function. If I assign the (to array converted param) to a local variable it doesn't work. Any ideas?
Didn't test well yet, but it might be a good start.
Thanks for the feedback @KRaymundus. As I said, I am adding tests at the moment in order to move faster without breaking anything and include features such as this one. I will probably finish adding tests end of this week and I will ping you then so we can take a look on your feedback and merge to master.
@RafaelMCarvalho @KRaymundus thank you for your input. The OR
filter has implemented on master. Check the documentation ;). Closing here.
Would be nice to have something like:
What do you think?