bmg 0.16.7 → 0.17.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 +4 -4
- data/Gemfile +3 -0
- data/lib/bmg/operator/image.rb +120 -9
- data/lib/bmg/operator/restrict.rb +4 -0
- data/lib/bmg/operator/shared/binary.rb +12 -1
- data/lib/bmg/operator/shared/nary.rb +9 -1
- data/lib/bmg/operator/shared/unary.rb +9 -1
- data/lib/bmg/relation.rb +4 -0
- data/lib/bmg/sequel/translator.rb +1 -1
- data/lib/bmg/sql/processor.rb +1 -0
- data/lib/bmg/sql/processor/bind.rb +23 -0
- data/lib/bmg/sql/processor/requalify.rb +1 -1
- data/lib/bmg/sql/relation.rb +6 -0
- data/lib/bmg/version.rb +2 -2
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d94c440e4e3c70b16735c6d31e3ba50a4be12430d347d9ac8cff6622bc64fb3
|
4
|
+
data.tar.gz: 1443c66b0c1c621f97b2f2f8bea2c522c07151ec4bbef71b45585078635c5b7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7eba5332a684097f8cd95a1c28463bbb1e5b004788bf3b3133a55a0c1cf1b5b5335a41924b9ba98cae10fe81f2c4b0ad70bb27d4f97618a8d18a7dbc0f48265f
|
7
|
+
data.tar.gz: 0241a9d8b895ca70df1a7f705ceecce062369810a8b4f60e1f314db0ab2888dc0060ad2f37697b7c83ab11cd2eaefd13e8445d1486d9827f294766bd9f3471aa
|
data/Gemfile
CHANGED
data/lib/bmg/operator/image.rb
CHANGED
@@ -12,7 +12,21 @@ module Bmg
|
|
12
12
|
|
13
13
|
# Whether we need to convert each image as an Array,
|
14
14
|
# instead of keeping a Relation instance
|
15
|
-
array: false
|
15
|
+
array: false,
|
16
|
+
|
17
|
+
# The strategy to use for actual image algorithm. Default is
|
18
|
+
# :refilter_right. Possible values are:
|
19
|
+
#
|
20
|
+
# - :index_right : builds a memory index with tuples from right, then
|
21
|
+
# passes left tuples and joins them with the index values.
|
22
|
+
#
|
23
|
+
# - :refilter_right : the left operand is materialized and all
|
24
|
+
# distinct values collected. The right operand is lately restricted
|
25
|
+
# to only those matching values. :index_right is then applied on
|
26
|
+
# resulting operabds. This option only applies when (optimized) `on`
|
27
|
+
# contains one attribute only. ; it fallbacks on :index_right
|
28
|
+
# otherwise.
|
29
|
+
strategy: :refilter_right
|
16
30
|
|
17
31
|
}
|
18
32
|
|
@@ -31,7 +45,55 @@ module Bmg
|
|
31
45
|
|
32
46
|
public
|
33
47
|
|
34
|
-
def each
|
48
|
+
def each(*args, &bl)
|
49
|
+
(options[:jit_optimized] ? self : jit_optimize)._each(*args, &bl)
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_ast
|
53
|
+
[ :image, left.to_ast, right.to_ast, as, on, options.dup ]
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def _each(*args, &bl)
|
59
|
+
case s = options[:strategy]
|
60
|
+
when :index_right then _each_index_right(*args, &bl)
|
61
|
+
when :refilter_right then _each_refilter_right(*args, &bl)
|
62
|
+
else
|
63
|
+
raise ArgumentError, "Unknown strategy `#{s}`"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def _each_index_right(*args, &bl)
|
68
|
+
left_rel, right_rel = self.left, self.right
|
69
|
+
_each_implem(left_rel, right_rel, *args, &bl)
|
70
|
+
end
|
71
|
+
|
72
|
+
def _each_refilter_right(*args, &bl)
|
73
|
+
left_rel, right_rel = self.left, self.right
|
74
|
+
|
75
|
+
# find matching keys on left and rebind the right
|
76
|
+
# placeholder to them
|
77
|
+
values = left_rel.map{|t| t[on.first] }
|
78
|
+
placeholder = options[:refilter_right][:placeholder]
|
79
|
+
right_rel = right_rel.bind(placeholder => values)
|
80
|
+
|
81
|
+
_each_implem(left_rel, right_rel, *args, &bl)
|
82
|
+
end
|
83
|
+
|
84
|
+
def _each_implem(left_rel, right_rel, *args)
|
85
|
+
# build right index
|
86
|
+
index = build_right_index(right_rel)
|
87
|
+
|
88
|
+
# each left with image from right index
|
89
|
+
left_rel.each do |tuple|
|
90
|
+
key = tuple_project(tuple, on)
|
91
|
+
image = index[key] || (options[:array] ? [] : empty_image)
|
92
|
+
yield tuple.merge(as => image)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_right_index(right)
|
35
97
|
index = Hash.new{|h,k| h[k] = empty_image }
|
36
98
|
right.each_with_object(index) do |t, index|
|
37
99
|
key = tuple_project(t, on)
|
@@ -42,15 +104,54 @@ module Bmg
|
|
42
104
|
ix[k] = v.to_a
|
43
105
|
end
|
44
106
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
107
|
+
index
|
108
|
+
end
|
109
|
+
|
110
|
+
protected ### jit_optimization
|
111
|
+
|
112
|
+
def jit_optimize
|
113
|
+
case s = options[:strategy]
|
114
|
+
when :index_right then jit_index_right
|
115
|
+
when :refilter_right then jit_refilter_right
|
116
|
+
else
|
117
|
+
raise ArgumentError, "Unknown strategy `#{s}`"
|
49
118
|
end
|
50
119
|
end
|
51
120
|
|
52
|
-
def
|
53
|
-
|
121
|
+
def jit_index_right
|
122
|
+
Image.new(
|
123
|
+
type,
|
124
|
+
left,
|
125
|
+
right,
|
126
|
+
as,
|
127
|
+
on,
|
128
|
+
options.merge(jit_optimized: true))
|
129
|
+
end
|
130
|
+
|
131
|
+
def jit_refilter_right
|
132
|
+
ltc = left.type.predicate.constants
|
133
|
+
rtc = right.type.predicate.constants
|
134
|
+
jit_allbut, jit_on = on.partition{|attr|
|
135
|
+
ltc.has_key?(attr) && rtc.has_key?(attr) && ltc[attr] == rtc[attr]
|
136
|
+
}
|
137
|
+
if jit_on.size == 1
|
138
|
+
p = Predicate.placeholder
|
139
|
+
Image.new(
|
140
|
+
type,
|
141
|
+
left.materialize,
|
142
|
+
right.restrict(Predicate.in(jit_on.first, p)).allbut(jit_allbut),
|
143
|
+
as,
|
144
|
+
jit_on,
|
145
|
+
options.merge(jit_optimized: true, refilter_right: { placeholder: p }))
|
146
|
+
else
|
147
|
+
Image.new(
|
148
|
+
type,
|
149
|
+
left,
|
150
|
+
right.allbut(jit_allbut),
|
151
|
+
as,
|
152
|
+
jit_on,
|
153
|
+
options.merge(jit_optimized: true, strategy: :index_right))
|
154
|
+
end
|
54
155
|
end
|
55
156
|
|
56
157
|
protected ### optimization
|
@@ -68,7 +169,7 @@ module Bmg
|
|
68
169
|
def _restrict(type, predicate)
|
69
170
|
on_as, rest = predicate.and_split([as])
|
70
171
|
if rest.tautology?
|
71
|
-
# push
|
172
|
+
# push index_right situation: on_as is still the full predicate
|
72
173
|
super
|
73
174
|
else
|
74
175
|
# rest makes no reference to `as` and can be pushed
|
@@ -126,6 +227,16 @@ module Bmg
|
|
126
227
|
Relation::InMemory.new(image_type, Set.new)
|
127
228
|
end
|
128
229
|
|
230
|
+
public
|
231
|
+
|
232
|
+
def to_s
|
233
|
+
options[:jit_optimized] ? super : jit_optimize.to_s
|
234
|
+
end
|
235
|
+
|
236
|
+
def inspect
|
237
|
+
options[:jit_optimized] ? super : jit_optimize.inspect
|
238
|
+
end
|
239
|
+
|
129
240
|
end # class Project
|
130
241
|
end # module Operator
|
131
242
|
end # module Bmg
|
@@ -3,9 +3,13 @@ module Bmg
|
|
3
3
|
module Binary
|
4
4
|
include Operator
|
5
5
|
|
6
|
+
def bind(binding)
|
7
|
+
_with_operands(left.bind(binding), right.bind(binding))
|
8
|
+
end
|
9
|
+
|
6
10
|
protected
|
7
11
|
|
8
|
-
|
12
|
+
attr_accessor :left, :right
|
9
13
|
|
10
14
|
def _visit(parent, visitor)
|
11
15
|
visitor.call(self, parent)
|
@@ -13,6 +17,13 @@ module Bmg
|
|
13
17
|
right.send(:_visit, self, visitor)
|
14
18
|
end
|
15
19
|
|
20
|
+
def _with_operands(left, right)
|
21
|
+
dup.tap{|d|
|
22
|
+
d.left = left
|
23
|
+
d.right = right
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
16
27
|
def operands
|
17
28
|
[left, right]
|
18
29
|
end
|
@@ -3,9 +3,17 @@ module Bmg
|
|
3
3
|
module Nary
|
4
4
|
include Operator
|
5
5
|
|
6
|
+
def bind(binding)
|
7
|
+
_with_operands(operands.map{|op| op.bind(binding) })
|
8
|
+
end
|
9
|
+
|
6
10
|
protected
|
7
11
|
|
8
|
-
|
12
|
+
attr_accessor :operands
|
13
|
+
|
14
|
+
def _with_operands(operands)
|
15
|
+
dup.tap{|d| d.operands = operands }
|
16
|
+
end
|
9
17
|
|
10
18
|
def _visit(parent, visitor)
|
11
19
|
visitor.call(self, parent)
|
@@ -3,15 +3,23 @@ module Bmg
|
|
3
3
|
module Unary
|
4
4
|
include Operator
|
5
5
|
|
6
|
+
def bind(binding)
|
7
|
+
_with_operand(operand.bind(binding))
|
8
|
+
end
|
9
|
+
|
6
10
|
protected
|
7
11
|
|
8
|
-
|
12
|
+
attr_accessor :operand
|
9
13
|
|
10
14
|
def _visit(parent, visitor)
|
11
15
|
visitor.call(self, parent)
|
12
16
|
operand._visit(self, visitor)
|
13
17
|
end
|
14
18
|
|
19
|
+
def _with_operand(operand)
|
20
|
+
dup.tap{|d| d.operand = operand }
|
21
|
+
end
|
22
|
+
|
15
23
|
def operands
|
16
24
|
[operand]
|
17
25
|
end
|
data/lib/bmg/relation.rb
CHANGED
@@ -50,7 +50,7 @@ module Bmg
|
|
50
50
|
dataset = dataset.select(*selection)
|
51
51
|
dataset = dataset.distinct if sexpr.distinct?
|
52
52
|
dataset = dataset.where(predicate) if predicate
|
53
|
-
dataset = dataset.group(
|
53
|
+
dataset = dataset.group(grouping) if grouping
|
54
54
|
dataset = dataset.order_by(*order) if order
|
55
55
|
dataset = dataset.limit(limit, offset == 0 ? nil : offset) if limit or offset
|
56
56
|
dataset
|
data/lib/bmg/sql/processor.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
class Processor
|
4
|
+
class Bind < Processor
|
5
|
+
|
6
|
+
def initialize(binding, builder)
|
7
|
+
super(builder)
|
8
|
+
@binding = binding
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_select_exp(sexpr)
|
12
|
+
if w = sexpr.where_clause
|
13
|
+
pred = Predicate::Grammar.sexpr(w.predicate.bind(@binding))
|
14
|
+
sexpr.with_update(:where_clause, [ :where_clause, pred ])
|
15
|
+
else
|
16
|
+
sexpr
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end # class Bind
|
21
|
+
end # class Processor
|
22
|
+
end # module Sql
|
23
|
+
end # module Bmg
|
data/lib/bmg/sql/relation.rb
CHANGED
data/lib/bmg/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bmg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernard Lambeau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: predicate
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '2.
|
19
|
+
version: '2.3'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 2.
|
22
|
+
version: 2.3.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '2.
|
29
|
+
version: '2.3'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 2.
|
32
|
+
version: 2.3.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: rake
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -222,6 +222,7 @@ files:
|
|
222
222
|
- lib/bmg/sql/nodes/with_spec.rb
|
223
223
|
- lib/bmg/sql/processor.rb
|
224
224
|
- lib/bmg/sql/processor/all.rb
|
225
|
+
- lib/bmg/sql/processor/bind.rb
|
225
226
|
- lib/bmg/sql/processor/clip.rb
|
226
227
|
- lib/bmg/sql/processor/constants.rb
|
227
228
|
- lib/bmg/sql/processor/distinct.rb
|