bmg 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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