Skip to content

Commit

Permalink
Add cross_product shortcut
Browse files Browse the repository at this point in the history
  * Sugar over join with empty on-list
  * Checks that there are no duplicate attributes between the relations
  • Loading branch information
felixyz committed Mar 6, 2024
1 parent 8e99975 commit 5725fac
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
9 changes: 9 additions & 0 deletions lib/bmg/algebra/shortcuts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ def left_join(right, on = [], *args)
self.left_join(right.rename(renaming), on.keys, *args)
end

def cross_product(right)
duplicates = self.type.attrlist & right.type.attrlist
unless duplicates.empty?
raise TypeError, "Cross product incompatible - duplicate attribute(s): #{duplicates.join(', ')}"
end

return join(right)
end

def matching(right, on = [])
return super unless on.is_a?(Hash)
renaming = Hash[on.map{|k,v| [v,k] }]
Expand Down
56 changes: 56 additions & 0 deletions spec/unit/algebra/shortcuts/test_cross_product.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require 'spec_helper'
module Bmg
module Algebra
describe Shortcuts, "cross_product" do

let(:left) {
Relation.new([
{ a: "foo", xyz: 1 },
{ a: "bar", xyz: 2 }
], Type::ANY.with_attrlist([:xyz, :b]))
}

let(:right) {
Relation.new([
{ c: "baz", d: 3 },
{ c: "zap", d: 4 }
], Type::ANY.with_attrlist([:c, :d]))
}

subject {
left.cross_product(right)
}

it 'compiles as expected' do
expect(subject).to be_a(Operator::Join)
expect(left_operand(subject)).to be(left)
expect(right_operand(subject)).to be(right)
expect(subject.send(:on)).to eql([])
end

it 'works as expected' do
expect(subject.to_set).to eql([
{ a: "bar", xyz: 2, c: "zap", d: 4 },
{ a: "foo", xyz: 1, c: "baz", d: 3 },
{ a: "foo", xyz: 1, c: "zap", d: 4 },
{ a: "bar", xyz: 2, c: "baz", d: 3 },
].to_set)
end

context 'with duplicate attributes' do
let(:right) {
Relation.new([
{ xyz: "baz", d: 3 },
{ xyz: "zap", d: 4 }
], Type::ANY.with_attrlist([:xyz, :d]))
}

it 'raises an error' do
expect{
left.cross_product(right)
}.to raise_error(Bmg::TypeError, /Cross product incompatible.*xyz/)
end
end
end
end
end

0 comments on commit 5725fac

Please sign in to comment.