Skip to content

Commit

Permalink
Merge pull request #59 from mdsol/feature/batches
Browse files Browse the repository at this point in the history
[MCC-233516] - add find_in_batches-like functiniality
  • Loading branch information
HonoreDB authored Jun 13, 2016
2 parents 1a482d8 + 12eda22 commit ccc5a21
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 0 deletions.
11 changes: 11 additions & 0 deletions lib/policy_machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,17 @@ def scoped_privileges(user_or_attribute, object_or_attribute, options = {})
end
end

##
# Search for and iterate over a collection in batches
def batch_find(type:, query: {}, config: {}, &blk)
if policy_machine_storage_adapter.respond_to?(:batch_find)
policy_machine_storage_adapter.batch_find(type, query, config, &blk)
else
batch_size = config.fetch(:batch_size, 1)
method(type.to_s.pluralize).call(query).each_slice(batch_size, &blk)
end
end

##
# Returns an array of all objects the given user (attribute)
# has the given operation on.
Expand Down
4 changes: 4 additions & 0 deletions lib/policy_machine_storage_adapters/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,10 @@ def scoped_privileges(user_or_attribute, object_or_attribute, options = {})
end
end

def batch_find(policy_object, query = {}, config = {}, &blk)
method("find_all_of_type_#{policy_object}").call(query).find_in_batches(config, &blk)
end

## Optimized version of PolicyMachine#scoped_privileges
# Returns all objects the user has the given operation on
# TODO: Support multiple policy classes here
Expand Down
91 changes: 91 additions & 0 deletions spec/support/shared_examples_policy_machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -793,4 +793,95 @@

end


describe 'batch_find' do

before do
@one_fish = policy_machine.create_object('one:fish')
@two_fish = policy_machine.create_object('two:fish')
@red_one = policy_machine.create_object('red:one')
@read = policy_machine.create_operation('read')
@write = policy_machine.create_operation('write')
@u1 = policy_machine.create_user('u1')
@ua = policy_machine.create_user_attribute('ua')
[@one_fish, @two_fish, @red_one].each do |object|
policy_machine.add_association(@ua, Set.new([@read]), object)
end
@oa = policy_machine.create_object_attribute('oa')
policy_machine.add_association(@ua, Set.new([@write]), @oa)
policy_machine.add_assignment(@u1, @ua)
policy_machine.add_assignment(@red_one, @oa)
end

context 'when given a block' do

it 'calls the block' do
expect do |spy|
policy_machine.batch_find(type: :object, query: { unique_identifier: 'one:fish' }, &spy)
end.to yield_control
end

context 'and search terms' do
it 'returns the matching records' do
policy_machine.batch_find(type: :object, query: { unique_identifier: 'one:fish' }) do |batch|
expect(batch.size).to eq 1
expect(batch.first.unique_identifier).to eq 'one:fish'
end
end
end

context 'and config options' do
it 'returns the correct batch size' do
policy_machine.batch_find(type: :object, config: { batch_size: 1 }) do |batch|
expect(batch.size).to eq 1
end

policy_machine.batch_find(type: :object, config: { batch_size: 3 }) do |batch|
expect(batch.size).to eq 3
end
end
end
end

context 'when not given a block' do

it 'returns an enumerator' do
result = policy_machine.batch_find(type: :object)
expect(result).to be_a Enumerator
end

it 'the results are chainable and returns the relevant results' do
enum = policy_machine.batch_find(type: :object)
results = enum.flat_map do |batch|
batch.map { |pe| pe.unique_identifier }
end
expected = %w(one:fish two:fish red:one)
expect(results).to include(*expected)
end

context 'but given search terms' do
it 'the results are chainable and returns the relevant results' do
enum = policy_machine.batch_find(type: :object, query: { unique_identifier: 'one:fish' })
results = enum.flat_map do |batch|
batch.map { |pe| pe.unique_identifier }
end
expected = 'one:fish'
expect(results.first).to eq(expected)
end
end

context 'but given config options' do
it 'resepects batch size configs while return all results' do
enum = policy_machine.batch_find(type: :object, config: { batch_size: 3})
results = enum.flat_map do |batch|
expect(batch.size).to eq 3
batch.map { |pe| pe.unique_identifier }
end
expected = %w(one:fish two:fish red:one)
expect(results).to include(*expected)
end
end

end
end
end

0 comments on commit ccc5a21

Please sign in to comment.