bmg 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6eb77419e8fb194a8698e79573474cb8bc54d0ea
4
- data.tar.gz: 5036c391503d6706639d9f084f32d0363c8c1658
3
+ metadata.gz: 31a0ebe96dae3801143c423e0b014bc9dee902b9
4
+ data.tar.gz: 6c4c003b7af5154301bf64f68f12e2bd7ab880f9
5
5
  SHA512:
6
- metadata.gz: 55a317e026aad03019afb486e0d06bbf25fc4157b5c8629cd06f183276251a55dbc287a57924a05a55db9f19832a4558ff45ff76a7ca2f053c255e02190d0117
7
- data.tar.gz: 5643a05c8dec82c94f49c69e8dfaf34f0a0d75fcf9018eaf1b470d7c3c5e42b83a783f92e89ca4e7241c6afb1ba9d0dafa6aa857dce1378613abac0fdf9273d4
6
+ metadata.gz: acaf31901fc7b3da45dfce9d7e1e23f1fe4ca86437db8c954538e3817fb4f4297825177ceb77d2fba60afabbb57e199fd0e932b1e944c5a750882c568fe0ea48
7
+ data.tar.gz: b27cd4e4d9132ac73a5fa27b0e03fa6badd197283b369aab9a463519df3b3f5092e3a669c856528063baa7f2a7eadc98c72aadd2a2a11b40f0a9614f0793c9cf
@@ -64,6 +64,15 @@ module Bmg
64
64
  end
65
65
  protected :_image
66
66
 
67
+ def join(right, on = [])
68
+ _join self.type.join(right.type, on), right, on
69
+ end
70
+
71
+ def _join(type, right, on)
72
+ Operator::Join.new(type, self, right, on)
73
+ end
74
+ protected :_join
75
+
67
76
  def matching(right, on = [])
68
77
  _matching self.type.matching(right, on), right, on
69
78
  end
@@ -9,6 +9,22 @@ module Bmg
9
9
  self.restrict(predicate)
10
10
  end
11
11
 
12
+ def prefix(prefix)
13
+ raise "Attrlist must be known to use `prefix`" unless self.type.knows_attrlist?
14
+ renaming = self.type.to_attrlist.each_with_object({}){|a,r|
15
+ r[a] = :"#{prefix}#{a}"
16
+ }
17
+ self.rename(renaming)
18
+ end
19
+
20
+ def suffix(suffix)
21
+ raise "Attrlist must be known to use `suffix`" unless self.type.knows_attrlist?
22
+ renaming = self.type.to_attrlist.each_with_object({}){|a,r|
23
+ r[a] = :"#{a}#{suffix}"
24
+ }
25
+ self.rename(renaming)
26
+ end
27
+
12
28
  end # module Shortcuts
13
29
  end # module Algebra
14
30
  end # module Bmg
@@ -72,6 +72,7 @@ require_relative 'operator/constants'
72
72
  require_relative 'operator/extend'
73
73
  require_relative 'operator/group'
74
74
  require_relative 'operator/image'
75
+ require_relative 'operator/join'
75
76
  require_relative 'operator/matching'
76
77
  require_relative 'operator/page'
77
78
  require_relative 'operator/project'
@@ -0,0 +1,59 @@
1
+ module Bmg
2
+ module Operator
3
+ #
4
+ # Join operator.
5
+ #
6
+ # Natural join, following relational algebra
7
+ #
8
+ class Join
9
+ include Operator::Binary
10
+
11
+ def initialize(type, left, right, on)
12
+ @type = type
13
+ @left = left
14
+ @right = right
15
+ @on = on
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :on
21
+
22
+ public
23
+
24
+ def each
25
+ index = Hash.new
26
+ right.each_with_object(index) do |t, index|
27
+ key = tuple_project(t, on)
28
+ index[key] ||= []
29
+ index[key] << t
30
+ end
31
+ left.each do |tuple|
32
+ key = tuple_project(tuple, on)
33
+ if to_join = index[key]
34
+ to_join.each do |right|
35
+ yield right.merge(tuple)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ def to_ast
42
+ [ :join, left.to_ast, right.to_ast, on ]
43
+ end
44
+
45
+ protected ### inspect
46
+
47
+ def args
48
+ [ on ]
49
+ end
50
+
51
+ private
52
+
53
+ def tuple_project(tuple, on)
54
+ TupleAlgebra.project(tuple, on)
55
+ end
56
+
57
+ end # class Join
58
+ end # module Operator
59
+ end # module Bmg
@@ -76,6 +76,6 @@ module Bmg
76
76
  TupleAlgebra.project(tuple, on)
77
77
  end
78
78
 
79
- end # class Project
79
+ end # class Matching
80
80
  end # module Operator
81
81
  end # module Bmg
@@ -4,11 +4,12 @@ module Bmg
4
4
  class Join < Processor
5
5
  include JoinSupport
6
6
 
7
- def initialize(right, builder)
7
+ def initialize(right, on, builder)
8
8
  super(builder)
9
9
  @right = right
10
+ @on = on
10
11
  end
11
- attr_reader :right
12
+ attr_reader :right, :on
12
13
 
13
14
  def call(sexpr)
14
15
  if unjoinable?(sexpr)
@@ -50,7 +51,7 @@ module Bmg
50
51
  end
51
52
 
52
53
  def join_from_clauses(left, right)
53
- joincon = join_predicate(left, right)
54
+ joincon = join_predicate(left, right, on)
54
55
  join = if joincon.tautology?
55
56
  [:cross_join, left.table_spec, right.table_spec]
56
57
  else
@@ -44,6 +44,17 @@ module Bmg
44
44
  _instance(type, builder, expr)
45
45
  end
46
46
 
47
+ def _join(type, right, on)
48
+ if right_expr = extract_compatible_sexpr(right)
49
+ right_expr = Processor::Requalify.new(builder).call(right_expr)
50
+ expr = before_use(self.expr)
51
+ expr = Processor::Join.new(right_expr, on, builder).call(expr)
52
+ _instance(type, builder, expr)
53
+ else
54
+ super
55
+ end
56
+ end
57
+
47
58
  def _matching(type, right, on)
48
59
  if right_expr = extract_compatible_sexpr(right)
49
60
  expr = before_use(self.expr)
@@ -15,12 +15,31 @@ module Bmg
15
15
  Keys.new(keys, false)
16
16
  end
17
17
 
18
+ def autowrap(oldtype, newtype, options)
19
+ sep = options[:split] || Operator::Autowrap::DEFAULT_OPTIONS[:split]
20
+ keys = @keys.map{|k|
21
+ k.map{|a| a.to_s.split(sep).first }.uniq.map(&:to_sym)
22
+ }
23
+ Keys.new(keys, false)
24
+ end
25
+
18
26
  def group(oldtype, newtype, attrs, as)
19
27
  keys = [ oldtype.attrlist - attrs ]
20
28
  keys += @keys.map{|k| (k & attrs).empty? ? k : (k - attrs) + [as] }
21
29
  Keys.new(keys, true)
22
30
  end
23
31
 
32
+ def join(oldtype, newtype, right_type, on)
33
+ return nil unless rkeys = right_type.keys
34
+ keys = []
35
+ @keys.each do |k1|
36
+ right_type.keys.each do |k2|
37
+ keys << (k1 + k2).uniq
38
+ end
39
+ end
40
+ Keys.new(keys, true)
41
+ end
42
+
24
43
  def project(oldtype, newtype, attrlist)
25
44
  keys = @keys.select{|k| k.all?{|a| attrlist.include?(a) } }
26
45
  keys = [newtype.attrlist] if keys.empty?
@@ -13,6 +13,12 @@ module Bmg
13
13
  attr_accessor :predicate
14
14
  protected :predicate=
15
15
 
16
+ def with_predicate(predicate)
17
+ dup.tap{|x|
18
+ x.predicate = predicate
19
+ }
20
+ end
21
+
16
22
  public ## attrlist
17
23
 
18
24
  attr_accessor :attrlist
@@ -71,7 +77,15 @@ module Bmg
71
77
  end
72
78
 
73
79
  def autowrap(options)
74
- ANY
80
+ sep = options[:split] || Operator::Autowrap::DEFAULT_OPTIONS[:split]
81
+ splitter = ->(a){ a.to_s.split(sep).first }
82
+ is_split = ->(a){ a.to_s.split(sep).size > 1 }
83
+ dup.tap{|x|
84
+ x.attrlist = self.attrlist.map(&splitter).uniq.map(&:to_sym) if knows_attrlist?
85
+ x.keys = self._keys.autowrap(self, x, options) if knows_keys?
86
+ autowrapped = self.predicate.free_variables.select(&is_split)
87
+ x.predicate = autowrapped.empty? ? self.predicate : self.predicate.and_split(autowrapped).last
88
+ }
75
89
  end
76
90
 
77
91
  def autosummarize(by, summarization)
@@ -110,6 +124,14 @@ module Bmg
110
124
  }
111
125
  end
112
126
 
127
+ def join(right, on)
128
+ dup.tap{|x|
129
+ x.attrlist = (knows_attrlist? and right.knows_attrlist?) ? (self.attrlist + right.attrlist).uniq : nil
130
+ x.predicate = self.predicate & right.predicate
131
+ x.keys = (knows_keys? and right.knows_keys?) ? self._keys.join(self, x, right, on) : nil
132
+ }
133
+ end
134
+
113
135
  def matching(right, on)
114
136
  self
115
137
  end
@@ -1,8 +1,8 @@
1
1
  module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 10
5
- TINY = 1
4
+ MINOR = 11
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
@@ -131,6 +131,7 @@ files:
131
131
  - lib/bmg/operator/extend.rb
132
132
  - lib/bmg/operator/group.rb
133
133
  - lib/bmg/operator/image.rb
134
+ - lib/bmg/operator/join.rb
134
135
  - lib/bmg/operator/matching.rb
135
136
  - lib/bmg/operator/page.rb
136
137
  - lib/bmg/operator/project.rb