Skip to content

Commit

Permalink
Merge pull request #17615 from NickLaMuro/custom_attributes_as_arel_v…
Browse files Browse the repository at this point in the history
…irtual_attributes

Changes custom_attribute virtual_attributes to support AREL/SQL
  • Loading branch information
kbrock authored Jun 21, 2018
2 parents 4ec0957 + 065405d commit 762abcf
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
5 changes: 5 additions & 0 deletions app/models/miq_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ def page_size
rpt_options.try(:fetch_path, :pdf, :page_size) || "a4"
end

def all_custom_attributes_are_virtual_sql_attributes?
ca_va_cols = CustomAttributeMixin.select_virtual_custom_attributes(cols)
ca_va_cols.all? { |custom_attribute| va_sql_cols.include?(custom_attribute) }
end

def load_custom_attributes
return unless db_klass < CustomAttributeMixin || Chargeback.db_is_chargeback?(db)

Expand Down
7 changes: 7 additions & 0 deletions app/models/miq_report/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,13 @@ def generate_basic_results(options = {})
# TODO: add once only_cols is fixed
# targets = targets.select(only_cols)
where_clause = MiqExpression.merge_where_clauses(self.where_clause, options[:where_clause])

# Remove custom_attributes as part of the `includes` if all of them exist
# in the select statement
if all_custom_attributes_are_virtual_sql_attributes?
remove_loading_relations_for_virtual_custom_attributes
end

rbac_opts = options.merge(
:targets => targets,
:filter => conditions,
Expand Down
34 changes: 28 additions & 6 deletions app/models/mixins/custom_attribute_mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,41 @@ def self.load_custom_attributes_for(cols)
def self.add_custom_attribute(custom_attribute)
return if respond_to?(custom_attribute)

virtual_column(custom_attribute.to_sym, :type => :string, :uses => :custom_attributes)
ca_sym = custom_attribute.to_sym
without_prefix = custom_attribute.sub(CUSTOM_ATTRIBUTES_PREFIX, "")
name_val, section = without_prefix.split(SECTION_SEPARATOR)
sanatized_column_alias = custom_attribute.tr('.', 'DOT').tr('/', 'BS').tr(':', 'CLN')
ca_arel = custom_attribute_arel(name_val, section, sanatized_column_alias)

define_method(custom_attribute.to_sym) do
custom_attribute_without_prefix = custom_attribute.sub(CUSTOM_ATTRIBUTES_PREFIX, "")
custom_attribute_without_section, section = custom_attribute_without_prefix.split(SECTION_SEPARATOR)
virtual_column(ca_sym, :type => :string, :uses => :custom_attributes, :arel => ca_arel)

where_args = {}
where_args[:name] = custom_attribute_without_section
define_method(ca_sym) do
return self[sanatized_column_alias] if has_attribute?(sanatized_column_alias)

where_args = {}
where_args[:name] = name_val
where_args[:section] = section if section

custom_attributes.find_by(where_args).try(:value)
end
end

def self.custom_attribute_arel(name_val, section, column_alias)
lambda do |t|
ca_field = CustomAttribute.arel_table

field_where = ca_field[:resource_id].eq(t[:id])
field_where = field_where.and(ca_field[:resource_type].eq(base_class.name))
field_where = field_where.and(ca_field[:name].eq(name_val))
field_where = field_where.and(ca_field[:section].eq(section)) if section

# Because there is a `find_by` in the `define_method` above, we are
# using a `take(1)` here as well, since a limit is assumed in each.
# Without it, there can be some invalid queries if more than one result
# is returned.
ca_field.project(:value).where(field_where).take(1).as(column_alias)
end
end
end

def self.to_human(column)
Expand Down

0 comments on commit 762abcf

Please sign in to comment.