Filtering ingredients by formula working
This commit is contained in:
parent
4ab24aa223
commit
70b6e97b87
@ -196,48 +196,29 @@ class IngredientsController < ApplicationController
|
||||
end
|
||||
|
||||
def prepare_ingredients
|
||||
@ingredients = filter_ingredients.includes(:ref_unit, :source)
|
||||
@ingredients = @project.ingredients.includes(:ref_unit, :source)
|
||||
.filter(@project, session[:filters])
|
||||
end
|
||||
|
||||
def prepare_nutrients
|
||||
@quantities = @project.quantities.where(primary: true)
|
||||
nutrients = filter_ingredients.compute_nutrients(@quantities)
|
||||
ingredients, requested_n, extra_n = @project.ingredients
|
||||
.filter(@project, session[:filters], @quantities)
|
||||
|
||||
@nutrients = {}
|
||||
@extra_nutrients = {}
|
||||
nutrients.each do |i, requested_n, extra_n|
|
||||
ingredients.each_with_index do |i, index|
|
||||
@nutrients[i] = []
|
||||
requested_n.each do |q_name, value|
|
||||
requested_n[index].each do |q_name, value|
|
||||
amount, unitname = value
|
||||
@nutrients[i] << [q_name, amount.nil? ? '-' : "#{amount} [#{unitname || '-'}]"]
|
||||
end
|
||||
|
||||
@extra_nutrients[i] = []
|
||||
extra_n.each do |q_name, value|
|
||||
extra_n[index].each do |q_name, value|
|
||||
amount, unitname = value
|
||||
@extra_nutrients[i] << [q_name, amount.nil? ? '-' : "#{amount} [#{unitname || '-'}]"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def filter_ingredients
|
||||
filters = session[:filters] || {}
|
||||
ingredients = @project.ingredients
|
||||
|
||||
if filters[:name].present?
|
||||
ingredients = ingredients.where("name LIKE ?", "%#{filters[:name]}%")
|
||||
end
|
||||
|
||||
if filters[:visibility].present?
|
||||
ingredients = ingredients.where(hidden: filters[:visibility] == "1" ? false : true)
|
||||
end
|
||||
|
||||
if filters[:nutrients].present?
|
||||
formula = Formula.new(self.project, filters[:nutrients], comparison: true)
|
||||
if formula.valid?
|
||||
end
|
||||
end
|
||||
|
||||
ingredients
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,6 @@
|
||||
class Ingredient < ActiveRecord::Base
|
||||
include BodyTracking::Formula
|
||||
|
||||
enum group: {
|
||||
other: 0,
|
||||
meat: 1
|
||||
@ -35,9 +37,36 @@ class Ingredient < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def self.compute_nutrients(requested_q)
|
||||
def self.filter(project, filters = {}, requested_q = [])
|
||||
ingredients = all
|
||||
|
||||
if filters[:name].present?
|
||||
ingredients = ingredients.where("name LIKE ?", "%#{filters[:name]}%")
|
||||
end
|
||||
|
||||
if filters[:visibility].present?
|
||||
ingredients = ingredients.where(hidden: filters[:visibility] == "1" ? false : true)
|
||||
end
|
||||
|
||||
formula_q = if filters[:nutrients].present?
|
||||
formula = Formula.new(project, filters[:nutrients])
|
||||
if formula.valid?
|
||||
project.quantities.new(name: '__internal_q', formula: filters[:nutrients])
|
||||
end
|
||||
end
|
||||
|
||||
if !requested_q.empty? || formula_q.present?
|
||||
result = self.compute_nutrients(requested_q, formula_q)
|
||||
requested_q.present? ? result : result[0]
|
||||
else
|
||||
ingredients
|
||||
end
|
||||
end
|
||||
|
||||
def self.compute_nutrients(requested_q, filter_q = nil)
|
||||
ingredients = all
|
||||
unchecked_q = requested_q.map { |q| [q, nil] }
|
||||
unchecked_q << [filter_q, nil] if filter_q
|
||||
|
||||
nutrients = Hash.new { |h,k| h[k] = {} }
|
||||
Nutrient.where(ingredient: ingredients).includes(:quantity, :unit)
|
||||
@ -90,10 +119,12 @@ class Ingredient < ActiveRecord::Base
|
||||
end
|
||||
|
||||
all_q = nutrients.merge(completed_q)
|
||||
ingredients.map do |i|
|
||||
requested_n = requested_q.map { |q| [q.name, all_q[q.name][i.id]] }
|
||||
extra_n = extra_q.map { |q_name| [q_name, all_q[q_name][i.id]] if all_q[q_name][i.id] }
|
||||
[i, requested_n, extra_n.compact]
|
||||
end
|
||||
[
|
||||
filter_q ? ingredients.to_a.keep_if { |i| all_q[filter_q.name][i.id] } : ingredients,
|
||||
ingredients.map { |i| requested_q.map { |q| [q.name, all_q[q.name][i.id]] } },
|
||||
ingredients.map do |i|
|
||||
extra_q.map { |q_name| [q_name, all_q[q_name][i.id]] if all_q[q_name][i.id] }
|
||||
end
|
||||
]
|
||||
end
|
||||
end
|
||||
|
@ -15,7 +15,7 @@
|
||||
<td style="width:100%;">
|
||||
<%= text_field_tag 'filters[nutrients]', session[:filters][:nutrients],
|
||||
placeholder: 'conditional expression including nutrients', size: 40,
|
||||
style: "box-sizing:border-box; width:100%;",
|
||||
:style => 'box-sizing:border-box; width:100%;',
|
||||
:onblur => '$("#filters_form").submit(); return false;' %>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -4,10 +4,9 @@ module BodyTracking
|
||||
QUANTITY_TTYPES = [:on_ident, :on_tstring_content, :on_const]
|
||||
|
||||
class Formula
|
||||
def initialize(project, formula, options = {})
|
||||
def initialize(project, formula)
|
||||
@project = project
|
||||
@formula = formula
|
||||
@options = options
|
||||
end
|
||||
|
||||
def validate
|
||||
@ -27,10 +26,10 @@ module BodyTracking
|
||||
identifiers << token
|
||||
when [:on_sp, :on_int, :on_rational, :on_float, :on_tstring_beg, :on_tstring_end,
|
||||
:on_lparen, :on_rparen].include?(ttype)
|
||||
when :on_op == ttype && ['+', '-', '*', '/', '%', '**'].include?(token)
|
||||
when :on_op == ttype && @options[:comparison] &&
|
||||
['==', '!=', '>', '<', '>=', '<=', '<=>', '===', '..', '...', '?:', 'and', 'or',
|
||||
'not', '&&', '||', '!'].include?(token)
|
||||
when :on_op == ttype &&
|
||||
['+', '-', '*', '/', '%', '**', '==', '!=', '>', '<', '>=', '<=', '<=>', '===',
|
||||
'..', '...', '?:', 'and', 'or', 'not', '&&', '||', '!'].include?(token)
|
||||
when :on_kw == ttype && ['and', 'or', 'not'].include?(token)
|
||||
else
|
||||
errors << [:disallowed_token, {token: token, ttype: ttype, location: location}]
|
||||
end
|
||||
@ -65,7 +64,7 @@ module BodyTracking
|
||||
|
||||
def calculate(inputs)
|
||||
paramed_formula = Ripper.lex(@formula).map do |*, ttype, token|
|
||||
QUANTITY_TTYPES.include?(ttype) ? "params['#{token}']" : token
|
||||
QUANTITY_TTYPES.include?(ttype) ? "params['#{token}'].to_d" : token
|
||||
end.join
|
||||
inputs.map { |i, values| [i, get_binding(values).eval(paramed_formula)] }
|
||||
end
|
||||
|
Reference in New Issue
Block a user