Skip to content

Commit

Permalink
Provide filter_results to refine a search
Browse files Browse the repository at this point in the history
rspec-puppet-facts has a pattern where it does a lot of small searches
for every OS. By doing a single complex FacterDB.get_facts call to get
the only supported operating systems and then further refining that
result it can use the cache provided by FacterDB.get_facts.

This is quite hacky now because it duplicates internals from JGrep to
avoid serializing to JSON and parsing that again. The conversions to
symbols and back to strings is also inefficient.
  • Loading branch information
ekohl committed Feb 27, 2024
1 parent 8f5eb6f commit 5e95739
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 0 deletions.
16 changes: 16 additions & 0 deletions lib/facterdb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,20 @@ def self.get_facts(filter = nil, cache = true)
end
result
end

# @param results [Array[Hash]] The results from a get_facts call
# @param filter [Object] The filter to convert to jgrep string
# @return [Array[Hash[Symbol, Any]]] Array of hashes of facts
def self.filter_results(results, filter)
# TODO: it's really inefficient to do to_s and to_sym all the time
database = results.map { |hash| hash.to_h { |k, v| [k.to_s, v] } }

# TODO: This duplicates JGrep.jgrep to avoid JSON.parse(database.to_json)
# JGrep should provide an API for that
expression = generate_filter_str(filter)
call_stack = JGrep::Parser.new(expression).execution_stack
filtered = database.filter { |document| JGrep.eval_statement(document, call_stack) }

filtered.map { |hash| hash.to_h { |k, v| [k.to_sym, v] } }
end
end
18 changes: 18 additions & 0 deletions spec/facter_db_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -353,4 +353,22 @@
end
end
end

describe '.filter_results' do
subject(:filtered) { FacterDB.filter_results(results, filter) }

let(:filters) { 'osfamily=Debian or osfamily=RedHat' }
let(:results) { FacterDB.get_facts(filters) }

# Just to make sure our results set contains what we want
it 'has both Debian and Red Hat in the unfiltered result' do
expect(results).to include(hash_including(osfamily: 'Debian')).and include(hash_including(osfamily: 'RedHat'))
end

context 'with filter for Debian' do

Check failure on line 368 in spec/facter_db_spec.rb

View workflow job for this annotation

GitHub Actions / rubocop

RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/6] (https://rspec.rubystyle.guide/#let-blocks, https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers)
let(:filter) { 'osfamily=Debian' }

it { is_expected.to include(hash_including(osfamily: 'Debian')).and not_include(hash_including(osfamily: 'RedHat')) }
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

RSpec::Matchers.define_negated_matcher :not_be_nil, :be_nil
RSpec::Matchers.define_negated_matcher :not_be_empty, :be_empty
RSpec::Matchers.define_negated_matcher :not_include, :include

def project_dir
File.dirname File.dirname(File.expand_path(__FILE__))
Expand Down

0 comments on commit 5e95739

Please sign in to comment.