def self.filter(filters)
return self.all if filters.nil?
# Build hash from params.
# Params pattern is :property_id/:product_property_value/:property_id..
# We cant use Hash[*args] because it overrides similar hash keys
# But we should have array of values for each property_id
hs = {}
by_intersect = []
arr = URI::decode(filters).split('/').map(&:to_i).map(&:to_s)
arr.each_with_index do |x,i|
next if i.odd?
hs[x] ||= []
hs[x] << arr[i+1]
end
# Produce query for each property
# We mix products that have any of property values
# And then filter by properties with SQL INTERSECT
hs.keys.each do |key|
values = []
hs[key].each do |val|
values << val
end
key = self.sanitize(key)
vals = values.map do |x|
self.sanitize(x)
end.join(", ")
condition = %{
"product_filters"."filter_type_id" = #{key} AND
"product_filters"."filter_value_id" IN (#{vals})
}
select_query = %{
SELECT "products"."id"
FROM "products"
INNER JOIN "product_filters"
ON "product_filters"."product_id" = "products"."id"
WHERE
#{condition}
}
by_intersect << select_query
end
# Combine all partial queries by property
# into one with INTERSECT
query = by_intersect.join("\nINTERSECT\n")
result = ActiveRecord::Base.connection.execute(query)
# As query result we get only products id
# Due to its faster than intersecting\ joining
# Heavy table with descriptions
ids = result.map{ |q| q.first.last }
# And then get exact products
Product.where(id: ids)
end