diff --git a/.gitignore b/.gitignore index 66d58b3..5804bf3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ test/version_tmp tmp vendor .byebug_history +.idea diff --git a/README.md b/README.md index 4c76fd7..0a86771 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ Country.european.republics.part_of_nato.order(id: :desc) ### Supported calculation methods - count + - pick - pluck - ids - minimum diff --git a/lib/frozen_record/base.rb b/lib/frozen_record/base.rb index 557b616..6bb61e7 100644 --- a/lib/frozen_record/base.rb +++ b/lib/frozen_record/base.rb @@ -103,7 +103,7 @@ def current_scope=(scope) end delegate :each, :find_each, :where, :first, :first!, :last, :last!, - :pluck, :ids, :order, :limit, :offset, :minimum, :maximum, :average, :sum, :count, + :pluck, :pick, :ids, :order, :limit, :offset, :minimum, :maximum, :average, :sum, :count, to: :current_scope def file_path diff --git a/lib/frozen_record/scope.rb b/lib/frozen_record/scope.rb index b2f7f0c..dd2d15c 100644 --- a/lib/frozen_record/scope.rb +++ b/lib/frozen_record/scope.rb @@ -78,6 +78,10 @@ def pluck(*attributes) end end + def pick(*attributes) + limit(1).pluck(*attributes).first + end + def ids pluck(primary_key) end diff --git a/spec/scope_spec.rb b/spec/scope_spec.rb index fa92e47..1f4071c 100644 --- a/spec/scope_spec.rb +++ b/spec/scope_spec.rb @@ -352,6 +352,84 @@ end + describe '.pick' do + + context 'when called with a single argument' do + + it 'returns the value of the first record' do + name = Country.pick(:name) + expect(name).to be == 'Canada' + end + + end + + context 'when called with multiple arguments' do + + it 'returns an array of the values of the first record' do + attributes = Country.pick(:id, :name) + expect(attributes).to be == [1, 'Canada'] + end + + end + + context 'when called without arguments' do + + it 'raises a NotImplementedError' do + expect { Country.pick }.to raise_error(NotImplementedError) + end + + end + + context 'when called on a scope' do + + it 'returns the attribute of the first matching record' do + name = Country.where(continent: 'Europe').pick(:name) + expect(name).to be == 'France' + end + + it 'honors the ordering' do + name = Country.order(name: :desc).pick(:name) + expect(name).to be == 'France' + end + + it 'honors the offset' do + name = Country.offset(1).pick(:name) + expect(name).to be == 'France' + end + + it 'does not alter the receiver scope' do + scope = Country.where(nato: true) + scope.pick(:name) + expect(scope.length).to be == 2 + end + + end + + context 'when no record matches' do + + it 'returns nil when called with a single argument' do + name = Country.where(name: 'not existing').pick(:name) + expect(name).to be_nil + end + + it 'returns nil when called with multiple arguments' do + attributes = Country.where(name: 'not existing').pick(:id, :name) + expect(attributes).to be_nil + end + + end + + context 'when passed an argument that is not an attribute' do + + it 'returns the result of calling the given method name' do + reverse_name = Country.pick(:reverse_name) + expect(reverse_name).to be == 'adanaC' + end + + end + + end + describe '.ids' do context 'when called with no arguments' do