class Twb::QuickFilter

Attributes

dataSource[R]
field[R]
includeNull[R]
inexMode[R]
inexclude[R]
kind[R]
name[R]
node[R]
type[R]
uiname[R]
values[R]

Public Class Methods

new(node,twb) click to toggle source
# File lib/twb/quickfilter.rb, line 31
def initialize(node,twb)
  init
  emit "\nFILTER:\n#{node}\n====="
  @node         = node
  filterClass   = @node['class']
  @type         = filterClass.gsub('-',' ').capitalize
  @kind         = @node['kind']
  fieldCode     = node['column']
  codedField    = Twb::CodedField.new(fieldCode) 
  fieldTech     = codedField.name
  inexclusions  = fieldTech =~ /^(Ex|In)clusions/
  @measureNames = ':Measure Names' == fieldTech
  srcTech       = codedField.dataSource
  @dataSource   = twb.datasource(srcTech)
  @dsAliases    = @dataSource.aliases
  field         = @measureNames || inexclusions ? fieldTech : @dataSource.field(fieldTech)
  uiname        = @dataSource.fieldUIName(fieldTech)
  @uiname       = @measureNames || inexclusions ? fieldTech : uiname.nil? ? fieldTech : uiname
  @field        = @uiname
  @includeNull  = if @node['include-null'].nil? 
                     true
                  elsif 'false' == @node['include-null']
                     false
                  else
                    true
                  end
  @values       = []
  enode      = @node.at_xpath('.//*[@user:ui-enumeration]')
  @inexclude = if enode.nil?
                  'Include'
               else case enode['user:ui-enumeration']
                      when 'inclusive' then 'Include'
                      when 'exclusive' then 'Exclude'
                      when  nil   then 'Include'
                      when 'all'  then 'Include'
                      else             'undefined'
                    end 
               end
  @inexMode  = enode.nil? ? 'Default' : 'Specified'
  emit "\n::  FIELD  :: #{field} == #{@uiname}   --  #{fieldTech}  --  #{codedField.rawCode}"
  emit "       filter class: #{filterClass}"
  emit "         field code: #{fieldCode}"
  emit "        coded field: #{codedField}"
  emit "         field tech: #{fieldTech}"
  emit "         field name: nil? #{@uiname.nil?}   #{@uiname}  "
  emit "           src tech: #{srcTech}"
  emit "       @measureNames: #{@measureNames}"
  emit "                 ds: #{@dataSource.uiname}"
  emit "              field: #{@uiname}"
  emit "         @inexclude: #{@inexclude}"
  emit " "
  aaa = case filterClass
    when 'relative-date' then resolveRelativeDate
    when 'quantitative'  then resolveQuantitative
    when 'categorical'   then resolveCategoricalValues
  end
end

Public Instance Methods

context?() click to toggle source
# File lib/twb/quickfilter.rb, line 89
def context?
  @iscontext ||= @node['context']
end
to_s() click to toggle source
# File lib/twb/quickfilter.rb, line 93
def to_s
    "%s => %s" % [uiname, values]
end

Private Instance Methods

filtersFromRangeNode(node) click to toggle source
# File lib/twb/quickfilter.rb, line 352
def filtersFromRangeNode node
  emit "########################## filtersFromRangeNode"
  unless @twbDomainsLoaded
    loadDomains 
  end
  # results = []
  emit  "filtersFromRangeNode"
  emit  "    from: #{node.attribute('from')}"
  emit  "    to. : #{node.attribute('to')}"
  from = node.attribute('from').text.gsub(/^"|"$/,'')
  to   = node.attribute(  'to').text.gsub(/^"|"$/,'')
  emit  "    from: #{from}"
  emit  "    to. : #{to}"
  if @twbDomainsLoaded
    # results = filtersInRange from, to
    filtersInRange from, to
  else
    range = "#{from},...,#{to}"
    recordValue range, range
  end
  # return results
end
filtersInRange(from, to) click to toggle source
# File lib/twb/quickfilter.rb, line 375
def filtersInRange from, to
  emit  "########################## filtersInRange"
  # results   = {}
  dsFields  = @twbFielddomains[@dataSource.uiname]
  emit  "dsFields    : #{dsFields}"
  if dsFields.nil? || dsFields.empty?
      alert  "#### ALERT #### - '#{@uiname}' FIELD DOMAIN VALUES FOR '#{@twb.name} DATASOURCE #{@dataSource.uiname} NOT LOADED ####"
      emit   @twbFieldDomains
      emit   "==========="
      emit   dsFields
      emit   "==========="
  else
      fieldVals = dsFields[@uiname].to_a
      if @dataSource.fieldHasAliases @uiname
        #-- resolve aliases
        dbValues = SortedSet.new
        aliases  = @dataSource.fieldAliases @uiname
        fieldVals.each do |fv|
          fvAliased = aliases.has_value? fv
          if fvAliased
            dbValues <<  aliases.key(fv)
          else 
            dbValues <<  fv
          end
        end
        $fieldVals = dbValues.to_a
      else
        #-- use domain values as returned
        $fieldVals = dsFields[@uiname].to_a
      end
      # domainVals = dsFields[field].to_a
      # #-- need to dealias (unalias?) the field domain values
      # dbVals = SortedSet.new
      # domainVals.each do |dv|
      emit  "field values: #{$fieldVals}"
      unless $fieldVals.nil? || $fieldVals.empty?
          values = $fieldVals
          f_i    = values.index from
          t_i    = values.index to
          emit  "      from: #{f_i} :: '#{from}'"
          emit  "        to: #{t_i} :: '#{to}'"
          badRange = f_i.nil? || t_i.nil?
          emit "badRange: #{badRange}"
          if badRange
            emit  "BAD RANGE"
          else
            tnames  = values[f_i..t_i]
            tnames.each do |tname|
              # results[tname] = @dataSource.deAlias(@uiname,tname) # $TableNameAliases[tname]
              recordValue tname, @dataSource.deAlias(@uiname,tname)
            end
            # emit  " filtersInRange  f:%-35s  t:%-s " % ["'#{from}:#{f_i}'", "'#{to}:#{t_i}'"]
            # emit  "         names:  #{results.keys}"
            # emit  "       aliases:  #{results.values}"
          end
      end
  end
  # return results
end
loadDomains() click to toggle source
# File lib/twb/quickfilter.rb, line 435
def loadDomains
  emit  "def loadDomains\n=="
  unless @twb.nil?
    loader            = Twb::Util::FieldDomainLoader.new
    @twbFielddomains  = loader.loadWorkbook @twb
    emit  "FIELD DOMAINS:: #{@twbFielddomains}\n=="
    @twbDomainsLoaded = true
  end
end
parseRangeVal(node) click to toggle source
# File lib/twb/quickfilter.rb, line 183
def parseRangeVal node
  return 'nil' if node.nil?
  text = node.text 
  if text.start_with?('#') 
    return text.gsub(/^[#]|[#]$/,'') 
  end
  num = text.to_f
  # num.negative? ? num.floor : num.ceil
  result = if num < 0
             num.floor
           else
             num.ceil
           end
  return result
end
quantRangeValues() click to toggle source
# File lib/twb/quickfilter.rb, line 169
def quantRangeValues
  min  = @node.at_xpath('min')
  max  = @node.at_xpath('max')
  emit "min: nil? %-6s  val: %-s " % [min.nil?,min]
  emit "max: nil? %-6s  val: %-s " % [max.nil?,max]
  minrv  = parseRangeVal min unless min.nil?
  maxrv  = parseRangeVal max unless max.nil?
  mintxt = min.nil? ? '' : max.nil? ? "At least: #{minrv}" : "#{minrv}"
  maxtxt = max.nil? ? '' : min.nil? ? "At most: #{maxrv}"  : ",...,#{maxrv}"
  recordValue "#{mintxt}#{maxtxt}"
  # emit   "#{mintxt}#{maxtxt}"
  # return "#{mintxt} #{maxtxt}"
end
recordValue(value, valias=nil) click to toggle source
# File lib/twb/quickfilter.rb, line 99
def recordValue value, valias=nil
  # puts "recordValue--: #{value} :: @'#{valias}'"
  # valias = value if valias.nil?
  @values <<  {:value => value, :alias => valias}
  # puts "recordValue--: done"
end
resolveCategoricalValues() click to toggle source

<filter class='categorical' column='[Sample - Superstore - English (Extract)].'>

<groupfilter from='&quot;East&quot;' function='range' level='[none:Region:nk]' to='&quot;West&quot;' user:ui-domain='relevant' user:ui-enumeration='inclusive' user:ui-marker='enumerate' />

</filter>

# File lib/twb/quickfilter.rb, line 202
def resolveCategoricalValues
  emit "########################## resolveCategoricalValues"
  emit "@measureNames: #{@measureNames}"
  if @node.element_children.empty?
    # <filter class='categorical' column='[Sample - Superstore].[Top Customers by Profit (copy)]' />
    recordValue 'All'
    return
  end
  firstChild = @node.at_xpath('./groupfilter')
  unless firstChild.nil?  # should not happen per 'if @node.element_children.empty?' above
      function   = firstChild['function']
      emit  "function  : #{function}"
      emit  node.to_s
      #-- single element filter
      case function
      when 'member'
          member = firstChild['member']
          value  = @measureNames ?  @dataSource.fieldUIName(Twb::CodedField.new(member).name) : member.gsub(/^"|"$/,'') 
          recordValue value, @dataSource.deAlias(@uiname,value)
      when 'empty-level'
        recordValue 'None'
      when 'range'
          filtersFromRangeNode firstChild
      when 'union'
          emit "No resolving to do here. 'union' function accommodated with collection of members"
      when 'except'
          emit "UNRESOLVED function: #{function}"
      when 'reorder-dimensionality'
          emit "UNRESOLVED function: #{function}, involved with Inclusions & Exclusions - complicated to handle"
      when 'level-members'
          uiEnum = firstChild['user:ui-enumeration']
          case uiEnum
          when 'all'
            recordValue 'All'
          else
            recordValue 'N/A'
            emit "###### ALERT - Unresolved Quick filter ######"
          end
      else
        recordValue "UNRESOLVED fn: #{function}"
      end
      # if 'member'.eql? function
      #   emit  "HANDLING SINGLE MEMBER FILTER"
      #   member = firstChild['member']
      #   value  = @measureNames ?  @dataSource.fieldUIName(Twb::CodedField.new(member).name) : member.gsub(/^"|"$/,'')
      #   alia   = @dataSource.deAlias(@uiname,value)
      #   emit  "value :%-25s =>  alias: %-s" % [value, alia]
      #   recordValue value, alia
      #   return
      # end
      # if 'empty-level' == function
      #   recordValue 'None', 'None'
      #   return
      # end
      # if 'range'.eql? function
      #   emit  "HANDLING RANGE 1st Child FILTER"
      #   # values = filtersFromRangeNode firstChild
      #   filtersFromRangeNode firstChild
      #   # values.each do |valMap|
      #   #   recordValue valMap[:value], valMap[:alias]
      #   # end
      # end
      #-- another single element filter
      # <groupfilter function="level-members" level="[none:Business Line:nk]" user:ui-enumeration="all" user:ui-marker="enumerate"/>
      # <filter class='categorical' column='[federated.1astm0q1hl2ydc1dyqhqq0igvxkp].[none:Business Line:nk]' context='true'>
      #   <groupfilter function='level-members'
      #                level='[none:Business Line:nk]'
      #                user:ui-enumeration='all'
      #                user:ui-exclude='true'
      #                user:ui-marker='enumerate' />
      # </filter>
      # <filter class='categorical' column='[federated.1astm0q1hl2ydc1dyqhqq0igvxkp].[none:Business Line:nk]' context='true'>
      #   <groupfilter function='level-members'
      #                level='[none:Business Line:nk]'
      #                user:ui-enumeration='all'
      #                user:ui-marker='enumerate' />
      # </filter>
      if 'level-members'.eql? function
        emit  "HANDLING level-members FILTER"
        #--
        # <filter class='categorical' column='[Sample - Superstore].[Top Customers by Profit (copy)]'>
        #   <groupfilter function='level-members' level='[Customer Name]' user:ui-enumeration='all' user:ui-marker='enumerate' />
        # </filter>
        #--
        # <filter class='categorical' column='[Sample - Superstore].[none:Customer Name:nk]'>
        #   <groupfilter function='level-members' level='[none:Customer Name:nk]' user:ui-enumeration='all' user:ui-marker='enumerate' />
        # </filter>
        #--
        # <filter class='categorical' column='[Sample - Superstore].[Top Customers by Profit (copy)]'>
        #   <groupfilter function='level-members' level='[Customer Name]' user:ui-enumeration='all' user:ui-exclude='true' user:ui-marker='enumerate' />
        # </filter>
        #--
        # <filter class='categorical' column='[Sample - Superstore].[none:Customer Name:nk]'>
        #   <groupfilter function='level-members' level='[none:Customer Name:nk]' user:ui-enumeration='all' user:ui-marker='enumerate' />
        # </filter>
        #--
        # <filter class='categorical' column='[Sample - Superstore].[Top Customers by Profit (copy)]'>
        #   <groupfilter function='except' user:ui-domain='relevant' user:ui-enumeration='exclusive' user:ui-marker='enumerate'>
        #     <groupfilter function='level-members' level='[Customer Name]' />
        #     <groupfilter function='union'>
        #       <groupfilter function='member' level='[Customer Name]' member='&quot;Adrian Barton&quot;' />
        #       <groupfilter function='member' level='[Customer Name]' member='&quot;Raymond Buch&quot;' />
        #     </groupfilter>
        #   </groupfilter>
        # </filter>
        #--
        uiEnum = firstChild['user:ui-enumeration']
        case uiEnum
        when 'all'
          recordValue 'All', 'All'
        when 'inclusive'
          @inexclude = 'Include'
        when 'exclusive'
          @inexclude = 'Exclude'
        end
      end
      #-- otherwise filter contains multiple elements
      #-- handle individual member elements
      elements = firstChild.xpath('.//groupfilter')
      elements.each do |element|
        function = element.attribute('function').text
        emit "element function: #{function}\n    node:\n#{element}"
        if 'member'.eql? function
          member = element.attribute('member').text
          name   = @measureNames ? @dataSource.fieldUIName(Twb::CodedField.new(member).name) : member.gsub(/^"|"$/,'')
          emit "%%%% member NAME:: #{name}"
          if '%null%' == name then name = 'Null' end
          alia  =  @dataSource.fieldAlias(@uiname,name) # $TableNameAliases[name]
          recordValue name, alia
        end
        if 'range'.eql? function
          emit "%%%% range element:: #{element}"
          t = filtersFromRangeNode element
          if t.empty?
            fromAttr = element['from']
            from     = fromAttr.nil? ? '' : fromAttr.gsub(/^[#"']|[#"']$/,'')
            toAttr   = element['to']
            to       = toAttr.nil?   ? '' : toAttr.gsub(/^[#"']|[#"']$/,'')
            range = "#{from},...,#{to}"
            recordValue range, range
          end 
          t.each do |name,alia|
            # emit true, "++++ range Name: %-20s   ALIAS: %-s " % [name, alia]
            # recordValue name, @dataSource.fieldAlias(@uiname,name)
          end
        end
      end
  end
end
resolveQuantitative() click to toggle source

<filter class='quantitative' column='[Sample - Superstore].' included-values='in-range'> <filter class='quantitative' column='[Sample - Superstore].' included-values='in-range'> <filter class='quantitative' column='[Sample - Superstore].' included-values='in-range'> <filter class='quantitative' column='[Sample - Superstore].' included-values='all' /> <filter class='quantitative' column='[Sample - Superstore].' included-values='non-null' /> <filter class='quantitative' column='[Sample - Superstore].' included-values='null' />

# File lib/twb/quickfilter.rb, line 158
def resolveQuantitative
  emit "resolveQuantitative"
  inclValues = @node['included-values']
  qvalues = if 'in-range' == inclValues
               quantRangeValues
            else
               "#{inclValues.capitalize} Values"
            end
  # recordValue qvalues, inclValues
end
resolveRelativeDate() click to toggle source

filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='-1' include-future='true' include-null='false' last-period='-1' period-type='day' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='-1' include-future='true' include-null='false' last-period='-1' period-type='year' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='-1' include-future='true' include-null='false' last-period='0' period-type='year' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='-2' include-future='true' include-null='false' last-period='0' period-type='day' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='-2' include-future='true' include-null='false' last-period='0' period-type='year' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='-6' include-future='true' include-null='false' last-period='0' period-type='day' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='0' include-future='false' include-null='false' last-period='0' period-type='year' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='0' include-future='true' include-null='false' last-period='0' period-type='day' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='0' include-future='true' include-null='false' last-period='0' period-type='year' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='0' include-future='true' include-null='false' last-period='2' period-type='day' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='0' include-future='true' include-null='false' last-period='2' period-type='year' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='0' include-future='true' include-null='false' last-period='4' period-type='day' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='1' include-future='true' include-null='false' last-period='1' period-type='day' /> filter class='relative-date' column='[Sample - Superstore].[none:Order Date:qk]' first-period='1' include-future='true' include-null='false' last-period='1' period-type='year' />

# File lib/twb/quickfilter.rb, line 121
def resolveRelativeDate
  emit "resolveRelativeDate"
  periodType  = @node['period-type'].nil? ? '' : @node['period-type']
  inclFuture  = @node['include-future'] == 'true'
  firstPeriod = @node['first-period'].to_i
  lastPeriod  = @node['last-period'].to_i
  sum         = firstPeriod + lastPeriod
  prod        = firstPeriod * lastPeriod
  periodTech  = "#{periodType} : #{firstPeriod} -> #{lastPeriod}"
  period      = periodTech
  if sum == 0 && prod == 0
    period = case periodType
               when 'day'  then "Today"
               else inclFuture ? "This #{periodType.capitalize}" : "#{periodType.capitalize} to date"
             end
  elsif firstPeriod == lastPeriod
     future = firstPeriod > 0
     reln   = future ? 'Next' : 'Previous'
     period = case periodType
                when 'day' then  future ? 'Tomorrow' : 'Yesterday' 
                else        "#{reln} #{periodType.capitalize}"
              end
  else
     span = lastPeriod - firstPeriod + 1
     future = firstPeriod == 0 
     reln   = future ? "Next" : "Last"
     period = "#{reln} #{span} #{periodType.capitalize}s"
  end
  recordValue period, periodTech
end