spec/unit/relation_spec.rb in rom-sql-0.7.0 vs spec/unit/relation_spec.rb in rom-sql-0.8.0

- old
+ new

@@ -4,197 +4,269 @@ include_context 'users and tasks' let(:users) { container.relations.users } let(:tasks) { container.relations.tasks } - before do - configuration.relation(:users) do - def sorted - order(:id) - end - end + context 'with schema', adapter: :sqlite do + let(:uri) { SQLITE_DB_URI } - configuration.relation(:tasks) - end + before do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String + end - describe '#dataset' do - it 'selects all qualified columns and sorts by pk' do - expect(users.dataset).to eql( - users.select(*users.columns).order(:users__id).dataset - ) + def sorted + order(:id) + end + end + + conf.relation(:tasks) end - end - describe '#sum' do - it 'delegates to dataset and return value' do - expect(users.dataset).to receive(:sum).with(:id).and_call_original - expect(users.sum(:id)).to eql(1) + describe '#dataset' do + it 'uses schema to infer default dataset' do + expect(container.relations[:users].dataset).to eql( + container.gateways[:default].dataset(:users).select(:id, :name).order(:users__id) + ) + end end end - describe '#min' do - it 'delegates to dataset and return value' do - users.insert id: 2, name: 'Oskar' + with_adapters do + context 'without schema' do + before do + conf.relation(:users) do + def sorted + order(:id) + end + end - expect(users.dataset).to receive(:min).with(:id).and_call_original - expect(users.min(:id)).to eql(1) - end - end + conf.relation(:tasks) + end - describe '#max' do - it 'delegates to dataset and return value' do - users.insert id: 2, name: 'Oskar' + describe '#associations' do + it 'returns an empty association set' do + expect(users.associations.elements).to be_empty + end + end - expect(users.dataset).to receive(:max).with(:id).and_call_original - expect(users.max(:id)).to eql(2) - end - end + describe '#dataset' do + it 'selects all qualified columns and sorts by pk' do + expect(users.dataset).to eql( + users.select(*users.columns).order(:users__id).dataset + ) + end + end - describe '#avg' do - it 'delegates to dataset and return value' do - users.insert id: 2, name: 'Oskar' + describe '#primary_key' do + it 'returns :id by default' do + expect(users.primary_key).to be(:id) + end - expect(users.dataset).to receive(:avg).with(:id).and_call_original - expect(users.avg(:id)).to eql(1.5) - end - end + it 'returns configured primary key from the schema' do + conf.relation(:other_users) do + schema(:users) do + attribute :name, ROM::SQL::Types::String.meta(primary_key: true) + end + end - describe '#distinct' do - it 'delegates to dataset and returns a new relation' do - expect(users.dataset).to receive(:distinct).with(:name).and_call_original - expect(users.distinct(:name)).to_not eq(users) - end - end + expect(container.relations[:other_users].primary_key).to be(:name) + end + end - describe '#exclude' do - it 'delegates to dataset and returns a new relation' do - expect(users.dataset) - .to receive(:exclude).with(name: 'Piotr').and_call_original - expect(users.exclude(name: 'Piotr')).to_not eq(users) - end - end + describe '#sum' do + it 'returns a sum' do + expect(users.sum(:id)).to eql(3) + end + end - describe '#invert' do - it 'delegates to dataset and returns a new relation' do - expect(users.dataset).to receive(:invert).and_call_original - expect(users.invert).to_not eq(users) - end - end + describe '#min' do + it 'returns a min' do + expect(users.min(:id)).to eql(1) + end + end - describe '#map' do - it 'yields tuples' do - result = users.map { |tuple| tuple[:name] } - expect(result).to eql(%w(Piotr)) - end - end + describe '#max' do + it 'delegates to dataset and return value' do + expect(users.max(:id)).to eql(2) + end + end - describe '#inner_join' do - it 'joins relations using inner join' do - conn[:users].insert(id: 2, name: 'Jane') + describe '#avg' do + it 'delegates to dataset and return value' do + expect(users.avg(:id)).to eql(1.5) + end + end - result = users.inner_join(:tasks, user_id: :id).select(:name, :title) + describe '#distinct' do + it 'delegates to dataset and returns a new relation' do + expect(users.dataset).to receive(:distinct).with(:name).and_call_original + expect(users.distinct(:name)).to_not eq(users) + end + end - expect(result.to_a).to match_array([ - { name: 'Piotr', title: 'Finish ROM' } - ]) - end + describe '#exclude' do + it 'delegates to dataset and returns a new relation' do + expect(users.dataset) + .to receive(:exclude).with(name: 'Jane').and_call_original + expect(users.exclude(name: 'Jane')).to_not eq(users) + end + end - it 'raises error when column names are ambiguous' do - expect { - users.inner_join(:tasks, user_id: :id).to_a - }.to raise_error(Sequel::DatabaseError, /column reference "id" is ambiguous/) - end - end + describe '#invert' do + it 'delegates to dataset and returns a new relation' do + expect(users.dataset).to receive(:invert).and_call_original + expect(users.invert).to_not eq(users) + end + end - describe '#left_join' do - it 'joins relations using left outer join' do - conn[:users].insert(id: 2, name: 'Jane') + describe '#map' do + it 'yields tuples' do + result = users.map { |tuple| tuple[:name] } + expect(result).to eql(%w(Jane Joe)) + end - result = users.left_join(:tasks, user_id: :id).select(:name, :title) + it 'plucks value' do + expect(users.map(:name)).to eql(%w(Jane Joe)) + end + end - expect(result.to_a).to match_array([ - { name: 'Piotr', title: 'Finish ROM' }, - { name: 'Jane', title: nil } - ]) - end - end + describe '#inner_join' do + it 'joins relations using inner join' do + result = users.inner_join(:tasks, user_id: :id).select(:name, :title) - describe '#project' do - it 'projects the dataset using new column names' do - projected = users.sorted.project(:name) + expect(result.to_a).to eql([ + { name: 'Jane', title: "Jane's task" }, + { name: 'Joe', title: "Joe's task" } + ]) + end - expect(projected.header).to match_array([:name]) - expect(projected.to_a).to eql([{ name: 'Piotr' }]) - end - end + it 'raises error when column names are ambiguous' do + expect { + users.inner_join(:tasks, user_id: :id).to_a + }.to raise_error(Sequel::DatabaseError, /is ambiguous/) + end + end - describe '#rename' do - it 'projects the dataset using new column names' do - renamed = users.sorted.rename(id: :user_id, name: :user_name) + describe '#left_join' do + it 'joins relations using left outer join' do + result = users.left_join(:tasks, user_id: :id).select(:name, :title) - expect(renamed.to_a).to eql([{ user_id: 1, user_name: 'Piotr' }]) - end - end + expect(result.to_a).to match_array([ + { name: 'Joe', title: "Joe's task" }, + { name: 'Jane', title: "Jane's task" } + ]) + end + end - describe '#prefix' do - it 'projects the dataset using new column names' do - prefixed = users.sorted.prefix(:user) + describe '#project' do + it 'projects the dataset using new column names' do + projected = users.sorted.project(:name) - expect(prefixed.to_a).to eql([{ user_id: 1, user_name: 'Piotr' }]) - end + expect(projected.header).to match_array([:name]) + expect(projected.first).to eql(name: 'Jane') + end + end - it 'uses singularized table name as the default prefix' do - prefixed = users.sorted.prefix + describe '#rename' do + it 'projects the dataset using new column names' do + renamed = users.sorted.rename(id: :user_id, name: :user_name) - expect(prefixed.to_a).to eql([{ user_id: 1, user_name: 'Piotr' }]) - end - end + expect(renamed.first).to eql(user_id: 1, user_name: 'Jane') + end + end - describe '#qualified_columns' do - it 'returns qualified column names' do - columns = users.sorted.prefix(:user).qualified_columns + describe '#prefix' do + it 'projects the dataset using new column names' do + prefixed = users.sorted.prefix(:user) - expect(columns).to eql([:users__id___user_id, :users__name___user_name]) - end + expect(prefixed.first).to eql(user_id: 1, user_name: 'Jane') + end - it 'returns projected qualified column names' do - columns = users.sorted.project(:id).prefix(:user).qualified_columns + it 'uses singularized table name as the default prefix' do + prefixed = users.sorted.prefix - expect(columns).to eql([:users__id___user_id]) - end - end + expect(prefixed.first).to eql(user_id: 1, user_name: 'Jane') + end + end - describe '#inspect' do - it 'includes dataset' do - expect(users.inspect).to include('dataset') - end - end + describe '#qualified_columns' do + it 'returns qualified column names' do + columns = users.sorted.prefix(:user).qualified_columns - describe '#unique?' do - before { tasks.delete } + expect(columns).to eql([:users__id___user_id, :users__name___user_name]) + end - it 'returns true when there is only one tuple matching criteria' do - expect(tasks.unique?(title: 'Task One')).to be(true) - end + it 'returns projected qualified column names' do + columns = users.sorted.project(:id).prefix(:user).qualified_columns - it 'returns true when there are more than one tuple matching criteria' do - tasks.insert(title: 'Task One') - expect(tasks.unique?(title: 'Task One')).to be(false) - end - end + expect(columns).to eql([:users__id___user_id]) + end + end - describe '#union' do - let(:relation1) { users.where(id: 1).select(:id, :name) } - let(:relation2) { users.where(id: 2).select(:id, :name) } + describe '#inspect' do + it 'includes dataset' do + expect(users.inspect).to include('dataset') + end + end - it 'unions two relations and returns a new relation' do - conn[:users].insert(id: 2, name: 'Jane') + describe '#unique?' do + before { tasks.delete } - result = relation1.union(relation2) + it 'returns true when there is only one tuple matching criteria' do + expect(tasks.unique?(title: 'Task One')).to be(true) + end - expect(result.to_a).to match_array([ - { id: 1, name: 'Piotr' }, - { id: 2, name: 'Jane' } - ]) + it 'returns true when there are more than one tuple matching criteria' do + tasks.insert(title: 'Task One') + expect(tasks.unique?(title: 'Task One')).to be(false) + end + end + + describe '#union' do + let(:relation1) { users.where(id: 1).select(:id, :name) } + let(:relation2) { users.where(id: 2).select(:id, :name) } + + it 'unions two relations and returns a new relation' do + result = relation1.union(relation2) + + expect(result.to_a).to match_array([ + { id: 1, name: 'Jane' }, + { id: 2, name: 'Joe' } + ]) + end + end + + describe '#pluck' do + it 'returns a list of values from a specific column' do + expect(users.pluck(:id)).to eql([1, 2]) + end + end + + describe '#by_pk' do + it 'restricts a relation by its PK' do + expect(users.by_pk(1).to_a).to eql([id: 1, name: 'Jane']) + end + + it 'is available as a view' do + expect(users.by_pk).to be_curried + end + end + + describe '#fetch' do + it 'returns a single tuple identified by the pk' do + expect(users.fetch(1)).to eql(id: 1, name: 'Jane') + end + + it 'raises when tuple was not found' do + expect { users.fetch(535315412) }.to raise_error(ROM::TupleCountMismatchError) + end + + it 'raises when more tuples were returned' do + expect { users.fetch([1, 2]) }.to raise_error(ROM::TupleCountMismatchError) + end + end end end end