Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract Expression Substitution code #6654

Merged
merged 2 commits into from
Feb 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 3 additions & 112 deletions app/controllers/application_controller/filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module ApplicationController::Filter
helper_method :calendar_needed? # because it is being called inside a render block
end

include MiqExpression::FilterSubstMixin

# Handle buttons pressed in the expression editor
def exp_button
@edit = session[:edit]
Expand Down Expand Up @@ -978,49 +980,12 @@ def quick_search

private

# Go thru an expression and replace the quick search tokens
def exp_replace_qs_tokens(exp, tokens)
key = exp.keys.first
if ["and", "or"].include?(key)
exp[key].each { |e| exp_replace_qs_tokens(e, tokens) }
elsif key == "not"
exp_replace_qs_tokens(exp[key], tokens)
elsif exp.key?(:token) && exp[key].key?("value")
token = exp[:token]
if tokens[token] # Only atoms included in tokens will have user input
value = tokens[token][:value] # Get the user typed value
if tokens[token][:value_type] == :bytes
value += ".#{tokens[token][:suffix] || "bytes"}" # For :bytes type, add in the suffix
end
exp[key]["value"] = value # Replace the exp value with the proper qs value
end
end
end

# Popup/open the quick search box
def quick_search_show
@exp_token = nil
@quick_search_active = true
@qs_exp_table = exp_build_table(@edit[:adv_search_applied][:exp], true)

# Create a hash to store quick search information by token
# and add in other quick search exp atom information.
@edit[:qs_tokens] = @qs_exp_table.select { |e| e.kind_of?(Array) }.each_with_object({}) do |e, acc|
token = e.last
acc[token] = {:value => nil}
exp = exp_find_by_token(@edit[:adv_search_applied][:exp], token)
first_exp = exp[exp.keys.first]

if first_exp.key?("field") # Base token settings on exp type
field = exp[exp.keys.first]["field"]
acc[token][:field] = field
acc[token][:value_type] = MiqExpression.get_col_info(field)[:format_sub_type]
elsif first_exp.key?("tag")
acc[token][:tag] = first_exp["tag"]
elsif first_exp.key?("count")
acc[token][:count] = first_exp["count"]
end
end
@edit[:qs_tokens] = create_tokens(@qs_exp_table, @edit[:adv_search_applied][:exp])

render :update do |page|
page.replace(:user_input_filter, :partial => "layouts/user_input_filter")
Expand Down Expand Up @@ -1107,58 +1072,6 @@ def exp_prefill_type(key, field)
end
end

# Build an array of expression symbols by recursively traversing the MiqExpression object
# and inserting sequential tokens for each expression part
def exp_build_table(exp, quick_search = false)
exp_table = []
if exp["and"]
exp_table.push("(")
exp["and"].each do |e|
exp_table += exp_build_table(e, quick_search)
exp_table.push("AND") unless e == exp["and"].last
end
exp_table.push(")")
elsif exp["or"]
exp_table.push("(")
exp["or"].each do |e|
exp_table += exp_build_table(e, quick_search)
exp_table.push("OR") unless e == exp["or"].last
end
exp_table.push(")")
elsif exp["not"]
@exp_token ||= 0
@exp_token += 1
exp[:token] = @exp_token
exp_table.push(quick_search ? "NOT" : ["NOT", @exp_token]) # No token if building quick search exp
exp_table.push("(") unless ["and", "or"].include?(exp["not"].keys.first) # No parens if and/or under me
exp_table += exp_build_table(exp["not"], quick_search)
exp_table.push(")") unless ["and", "or"].include?(exp["not"].keys.first) # No parens if and/or under me
else
@exp_token ||= 0
@exp_token += 1
exp[:token] = @exp_token
if exp["???"] # Found a new expression part
exp_table.push(["???", @exp_token])
@edit[@expkey][:exp_token] = @exp_token # Save the token value for the view
@edit[:edit_exp] = copy_hash(exp) # Save the exp part for the view
exp_set_fields(@edit[:edit_exp]) # Set the fields for a new exp part
else
if quick_search # Separate out the user input fields if doing a quick search
human_exp = MiqExpression.to_human(exp)
if human_exp.include?("<user input>")
exp_table.push(human_exp.split("<user input>").join(""))
exp_table.push([:user_input, @exp_token])
else
exp_table.push(human_exp)
end
else # Not quick search, add token to the expression
exp_table.push([MiqExpression.to_human(exp), @exp_token])
end
end
end
exp_table
end

# Remove :token keys from an expression before setting in a record
def exp_remove_tokens(exp)
if exp.kind_of?(Array) # Is this and AND or OR
Expand All @@ -1180,28 +1093,6 @@ def exp_remove_tokens(exp)
end
end

# Find an expression atom based on the token
def exp_find_by_token(exp, token, parent_is_not = false)
if exp.kind_of?(Array) # Is this and AND or OR
exp.each do |e| # yes, check each array item
ret_exp = exp_find_by_token(e, token) # Look for token
return ret_exp unless ret_exp.nil? # Return if we found it
end
return nil # Didn't find it in the array, return nil
elsif exp[:token] && exp[:token] == token # This is the token exp
@parent_is_not = true if parent_is_not # Remember that token exp's parent is a NOT
return exp # return it
elsif exp["not"]
return exp_find_by_token(exp["not"], token, true) # Look for token under NOT (indicate we are a NOT)
elsif exp["and"]
return exp_find_by_token(exp["and"], token) # Look for token under AND
elsif exp["or"]
return exp_find_by_token(exp["or"], token) # Look for token under OR
else
return nil
end
end

# Set the fields for the expression editor based on the current expression
def exp_set_fields(exp)
exp.delete(:token) # Clear out the token key, if present
Expand Down
120 changes: 120 additions & 0 deletions app/models/miq_expression/filter_subst_mixin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
module MiqExpression::FilterSubstMixin
include ActiveSupport::Concern
# Build an array of expression symbols by recursively traversing the MiqExpression object
# and inserting sequential tokens for each expression part
def exp_build_table(exp, quick_search = false)
exp_table = []
if exp["and"]
exp_table.push("(")
exp["and"].each do |e|
exp_table += exp_build_table(e, quick_search)
exp_table.push("AND") unless e == exp["and"].last
end
exp_table.push(")")
elsif exp["or"]
exp_table.push("(")
exp["or"].each do |e|
exp_table += exp_build_table(e, quick_search)
exp_table.push("OR") unless e == exp["or"].last
end
exp_table.push(")")
elsif exp["not"]
@exp_token ||= 0
@exp_token += 1
exp[:token] = @exp_token
exp_table.push(quick_search ? "NOT" : ["NOT", @exp_token]) # No token if building quick search exp
exp_table.push("(") unless ["and", "or"].include?(exp["not"].keys.first) # No parens if and/or under me
exp_table += exp_build_table(exp["not"], quick_search)
exp_table.push(")") unless ["and", "or"].include?(exp["not"].keys.first) # No parens if and/or under me
else
@exp_token ||= 0
@exp_token += 1
exp[:token] = @exp_token
if exp["???"] # Found a new expression part
exp_table.push(["???", @exp_token])
exp_context[@expkey][:exp_token] = @exp_token # Save the token value for the view
exp_context[:edit_exp] = copy_hash(exp) # Save the exp part for the view
exp_set_fields(exp_context[:edit_exp]) # Set the fields for a new exp part
else
if quick_search # Separate out the user input fields if doing a quick search
human_exp = MiqExpression.to_human(exp)
if human_exp.include?("<user input>")
exp_table.push(human_exp.split("<user input>").join(""))
exp_table.push([:user_input, @exp_token])
else
exp_table.push(human_exp)
end
else # Not quick search, add token to the expression
exp_table.push([MiqExpression.to_human(exp), @exp_token])
end
end
end
exp_table
end

# Go thru an expression and replace the quick search tokens
def exp_replace_qs_tokens(exp, tokens)
key = exp.keys.first
if ["and", "or"].include?(key)
exp[key].each { |e| exp_replace_qs_tokens(e, tokens) }
elsif key == "not"
exp_replace_qs_tokens(exp[key], tokens)
elsif exp.key?(:token) && exp[key].key?("value")
token = exp[:token]
if tokens[token] # Only atoms included in tokens will have user input
value = tokens[token][:value] # Get the user typed value
if tokens[token][:value_type] == :bytes
value += ".#{tokens[token][:suffix] || "bytes"}" # For :bytes type, add in the suffix
end
exp[key]["value"] = value # Replace the exp value with the proper qs value
end
end
end

# Find an expression atom based on the token
def exp_find_by_token(exp, token, parent_is_not = false)
if exp.kind_of?(Array) # Is this and AND or OR
exp.each do |e| # yes, check each array item
ret_exp = exp_find_by_token(e, token) # Look for token
return ret_exp unless ret_exp.nil? # Return if we found it
end
return nil # Didn't find it in the array, return nil
elsif exp[:token] && exp[:token] == token # This is the token exp
@parent_is_not = true if parent_is_not # Remember that token exp's parent is a NOT
return exp # return it
elsif exp["not"]
return exp_find_by_token(exp["not"], token, true) # Look for token under NOT (indicate we are a NOT)
elsif exp["and"]
return exp_find_by_token(exp["and"], token) # Look for token under AND
elsif exp["or"]
return exp_find_by_token(exp["or"], token) # Look for token under OR
else
return nil
end
end

# Create a hash to store quick search information by token
# and add in other quick search exp atom information.
def create_tokens(exp_table, orig_exp)
exp_table.select { |e| e.kind_of?(Array) }.each_with_object({}) do |e, acc|
token = e.last
acc[token] = {:value => nil}
exp = exp_find_by_token(orig_exp, token)
first_exp = exp[exp.keys.first]

if first_exp.key?("field") # Base token settings on exp type
field = exp[exp.keys.first]["field"]
acc[token][:field] = field
acc[token][:value_type] = MiqExpression.get_col_info(field)[:format_sub_type]
elsif first_exp.key?("tag")
acc[token][:tag] = first_exp["tag"]
elsif first_exp.key?("count")
acc[token][:count] = first_exp["count"]
end
end
end

def exp_context
@edit
end
end