bmg 0.12.0 → 0.13.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/lib/bmg/algebra.rb +2 -0
- data/lib/bmg/relation/empty.rb +4 -0
- data/lib/bmg/sequel.rb +11 -8
- data/lib/bmg/sequel/translator.rb +11 -8
- data/lib/bmg/sql/builder.rb +12 -0
- data/lib/bmg/sql/grammar.sexp.yml +3 -3
- data/lib/bmg/sql/nodes/select_exp.rb +2 -2
- data/lib/bmg/sql/nodes/select_list.rb +11 -2
- data/lib/bmg/sql/nodes/select_star.rb +1 -1
- data/lib/bmg/sql/nodes/set_operator.rb +3 -3
- data/lib/bmg/sql/processor.rb +1 -0
- data/lib/bmg/sql/processor/constants.rb +32 -0
- data/lib/bmg/sql/processor/join_support.rb +2 -4
- data/lib/bmg/sql/processor/merge.rb +8 -0
- data/lib/bmg/sql/processor/semi_join.rb +2 -3
- data/lib/bmg/sql/processor/where.rb +25 -5
- data/lib/bmg/sql/relation.rb +6 -0
- data/lib/bmg/version.rb +1 -1
- metadata +4 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7cf04c07c2f88598d086c9eb174c857995a3646
|
4
|
+
data.tar.gz: 368fdda422f043d57c7da57f5019b4682e9d37eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ef7574e4dfe6e30619310daf922e16ca20f5721f2d4f339a13fd8077520316215d8306f6b7150a3df5648944163fc5bb9329d40663b6ccf4be1eeba7d26af4c
|
7
|
+
data.tar.gz: a5c71d8cfb1b9e52ab360b3deaffc6c9986b7388154b78141256a83b949300b329c433f7a265cf97d6ab1ba7433ebd08f15e0a549fb39f2b02f19cb2d5cd5a7b
|
data/lib/bmg/algebra.rb
CHANGED
@@ -2,6 +2,7 @@ module Bmg
|
|
2
2
|
module Algebra
|
3
3
|
|
4
4
|
def allbut(butlist = [])
|
5
|
+
return self if butlist.empty?
|
5
6
|
_allbut self.type.allbut(butlist), butlist
|
6
7
|
end
|
7
8
|
|
@@ -142,6 +143,7 @@ module Bmg
|
|
142
143
|
protected :_restrict
|
143
144
|
|
144
145
|
def union(other, options = {})
|
146
|
+
return self if other.is_a?(Relation::Empty)
|
145
147
|
_union self.type.union(other.type), other, options
|
146
148
|
end
|
147
149
|
|
data/lib/bmg/relation/empty.rb
CHANGED
data/lib/bmg/sequel.rb
CHANGED
@@ -7,9 +7,13 @@ module Bmg
|
|
7
7
|
|
8
8
|
def sequel(*args, &bl)
|
9
9
|
source, sequel_db, type = sequel_params(*args, &bl)
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
if type
|
11
|
+
builder = Sql::Builder.new
|
12
|
+
sexpr = builder.select_all(type.to_attrlist, source)
|
13
|
+
Sequel::Relation.new(type, builder, sexpr, sequel_db).spied(Bmg.main_spy)
|
14
|
+
else
|
15
|
+
Bmg::Relation.new(source)
|
16
|
+
end
|
13
17
|
end
|
14
18
|
module_function :sequel
|
15
19
|
|
@@ -18,16 +22,15 @@ module Bmg
|
|
18
22
|
sequel_db = source.db if sequel_db.nil? and source.is_a?(::Sequel::Dataset)
|
19
23
|
raise ArgumentError, "A Sequel::Database object is required" if sequel_db.nil?
|
20
24
|
raise ArgumentError, "Type's attrlist must be known (#{type})" if type && !type.knows_attrlist?
|
21
|
-
type = infer_type
|
25
|
+
type = infer_type(sequel_db, source) if type.nil?
|
22
26
|
[source, sequel_db, type]
|
23
27
|
end
|
24
28
|
module_function :sequel_params
|
25
29
|
|
26
|
-
def infer_type
|
27
|
-
|
28
|
-
TypeInference.new(sequel_db).call(source)
|
30
|
+
def infer_type(sequel_db, source)
|
31
|
+
TypeInference.new(sequel_db).call(source) if source.is_a?(Symbol)
|
29
32
|
end
|
30
|
-
module_function :infer_type
|
33
|
+
module_function :infer_type
|
31
34
|
|
32
35
|
end
|
33
36
|
|
@@ -28,9 +28,9 @@ module Bmg
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def on_set_operator(sexpr)
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
sexpr.tail_exprs.inject(apply(sexpr.head_expr)) do |left,right|
|
32
|
+
left.send(sexpr.first, apply(right), all: sexpr.all?, from_self: false)
|
33
|
+
end
|
34
34
|
end
|
35
35
|
alias :on_union :on_set_operator
|
36
36
|
alias :on_intersect :on_set_operator
|
@@ -65,10 +65,13 @@ module Bmg
|
|
65
65
|
def on_select_item(sexpr)
|
66
66
|
left = apply(sexpr.left)
|
67
67
|
right = apply(sexpr.right)
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
case kind = sexpr.left.first
|
69
|
+
when :qualified_name
|
70
|
+
left.column == right.value ? left : ::Sequel.as(left, right)
|
71
|
+
when :literal
|
71
72
|
::Sequel.as(left, right)
|
73
|
+
else
|
74
|
+
raise NotImplementedError, "Unexpected select item `#{kind}`"
|
72
75
|
end
|
73
76
|
end
|
74
77
|
|
@@ -85,7 +88,7 @@ module Bmg
|
|
85
88
|
end
|
86
89
|
|
87
90
|
def on_table_name(sexpr)
|
88
|
-
::Sequel.
|
91
|
+
::Sequel.expr(sexpr.last.to_sym)
|
89
92
|
end
|
90
93
|
|
91
94
|
def on_cross_join(sexpr)
|
@@ -102,7 +105,7 @@ module Bmg
|
|
102
105
|
end
|
103
106
|
|
104
107
|
def on_table_as(sexpr)
|
105
|
-
::Sequel.as(::Sequel.
|
108
|
+
::Sequel.as(::Sequel.expr(sexpr.table_name.to_sym), ::Sequel.identifier(sexpr.as_name))
|
106
109
|
end
|
107
110
|
|
108
111
|
def on_subquery_as(sexpr)
|
data/lib/bmg/sql/builder.rb
CHANGED
@@ -67,6 +67,13 @@ module Bmg
|
|
67
67
|
end
|
68
68
|
builder :select_list
|
69
69
|
|
70
|
+
def select_literal_item(literal, as)
|
71
|
+
[:select_item,
|
72
|
+
literal(literal),
|
73
|
+
column_name(as.to_s)]
|
74
|
+
end
|
75
|
+
builder :select_literal_item
|
76
|
+
|
70
77
|
def select_item(qualifier, name, as = name)
|
71
78
|
[:select_item,
|
72
79
|
qualified_name(qualifier, name.to_s),
|
@@ -158,6 +165,11 @@ module Bmg
|
|
158
165
|
end
|
159
166
|
builder :offset_clause
|
160
167
|
|
168
|
+
def literal(lit)
|
169
|
+
[:literal, lit]
|
170
|
+
end
|
171
|
+
builder :literal
|
172
|
+
|
161
173
|
def from_self(sexpr)
|
162
174
|
Processor::FromSelf.new(self).call(sexpr)
|
163
175
|
end
|
@@ -14,13 +14,13 @@ rules:
|
|
14
14
|
- intersect
|
15
15
|
- select_exp
|
16
16
|
union:
|
17
|
-
- [ all, nonjoin_exp
|
17
|
+
- [ all, nonjoin_exp+ ]
|
18
18
|
all:
|
19
19
|
- truth_value
|
20
20
|
except:
|
21
|
-
- [ set_quantifier, nonjoin_exp
|
21
|
+
- [ set_quantifier, nonjoin_exp+ ]
|
22
22
|
intersect:
|
23
|
-
- [ set_quantifier, nonjoin_exp
|
23
|
+
- [ set_quantifier, nonjoin_exp+ ]
|
24
24
|
join_exp:
|
25
25
|
- cross_join
|
26
26
|
- inner_join
|
@@ -3,10 +3,19 @@ module Bmg
|
|
3
3
|
module SelectList
|
4
4
|
include Expr
|
5
5
|
|
6
|
-
def desaliaser
|
6
|
+
def desaliaser(for_predicate = false)
|
7
7
|
->(a){
|
8
8
|
item = sexpr_body.find{|item| item.as_name.to_s == a.to_s }
|
9
|
-
item && item.left
|
9
|
+
return nil unless left = item && item.left
|
10
|
+
return left unless for_predicate
|
11
|
+
case left.first
|
12
|
+
when :literal
|
13
|
+
Predicate::Grammar.sexpr([:literal, left.last])
|
14
|
+
when :qualified_name
|
15
|
+
Predicate::Grammar.sexpr([:qualified_identifier, left.qualifier.to_sym, left.as_name.to_sym])
|
16
|
+
else
|
17
|
+
raise "Unexpected select_item `#{left}`"
|
18
|
+
end
|
10
19
|
}
|
11
20
|
end
|
12
21
|
|
data/lib/bmg/sql/processor.rb
CHANGED
@@ -70,6 +70,7 @@ end
|
|
70
70
|
require_relative 'processor/distinct'
|
71
71
|
require_relative 'processor/all'
|
72
72
|
require_relative 'processor/clip'
|
73
|
+
require_relative 'processor/constants'
|
73
74
|
require_relative 'processor/star'
|
74
75
|
require_relative 'processor/rename'
|
75
76
|
require_relative 'processor/order_by'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
class Processor
|
4
|
+
class Constants < Processor
|
5
|
+
|
6
|
+
def initialize(constants, builder)
|
7
|
+
super(builder)
|
8
|
+
@constants = constants
|
9
|
+
end
|
10
|
+
attr_reader :constants
|
11
|
+
|
12
|
+
def on_set_operator(sexpr)
|
13
|
+
apply(builder.from_self(sexpr))
|
14
|
+
end
|
15
|
+
alias :on_union :on_set_operator
|
16
|
+
alias :on_except :on_set_operator
|
17
|
+
alias :on_intersect :on_set_operator
|
18
|
+
|
19
|
+
def on_select_star(sexpr)
|
20
|
+
raise NotImplementedError, "Constants on * is not supported"
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_select_list(sexpr)
|
24
|
+
sexpr + constants.each_pair.map{|(k,v)|
|
25
|
+
builder.select_literal_item(v, k)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
end # class Constants
|
30
|
+
end # class Processor
|
31
|
+
end # module Sql
|
32
|
+
end # module Bmg
|
@@ -13,12 +13,10 @@ module Bmg
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def join_predicate(left, right, commons)
|
16
|
-
left_d, right_d = left.desaliaser, right.desaliaser
|
16
|
+
left_d, right_d = left.desaliaser(true), right.desaliaser(true)
|
17
17
|
commons.to_a.inject(tautology){|cond, attr|
|
18
18
|
left_attr, right_attr = left_d[attr], right_d[attr]
|
19
|
-
|
20
|
-
right_p = Predicate::Factory.qualified_identifier(right_attr.qualifier, right_attr.as_name)
|
21
|
-
cond &= Predicate::Factory.eq(left_p, right_p)
|
19
|
+
cond &= Predicate::Factory.eq(left_attr, right_attr)
|
22
20
|
}
|
23
21
|
end
|
24
22
|
|
@@ -23,11 +23,19 @@ module Bmg
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def on_nonjoin_exp(sexpr)
|
26
|
+
left_attrs = sexpr.to_attr_list.map(&:to_s).sort
|
27
|
+
right_attrs = @right.to_attr_list.map(&:to_s).sort
|
28
|
+
unless left_attrs == right_attrs
|
29
|
+
raise "Operands are not union compatible: #{left_attrs.inspect} vs. #{right_attrs.inspect}"
|
30
|
+
end
|
31
|
+
|
26
32
|
reordered = Reorder.new(sexpr.to_attr_list, builder).call(@right)
|
27
33
|
if @right.with_exp?
|
28
34
|
[ :with_exp,
|
29
35
|
reordered.with_spec,
|
30
36
|
[ @kind, modifier, sexpr, reordered.select_exp ] ]
|
37
|
+
elsif sexpr.first == @kind && sexpr.set_quantifier == modifier
|
38
|
+
sexpr.dup + [ reordered ]
|
31
39
|
else
|
32
40
|
[ @kind, modifier, sexpr, reordered ]
|
33
41
|
end
|
@@ -40,9 +40,8 @@ module Bmg
|
|
40
40
|
if commons.size == 0
|
41
41
|
builder.exists(subquery)
|
42
42
|
elsif commons.size == 1
|
43
|
-
identifier = left.desaliaser[commons.to_a.first]
|
44
|
-
|
45
|
-
Predicate::Factory.in(qualified, subquery)
|
43
|
+
identifier = left.desaliaser(true)[commons.to_a.first]
|
44
|
+
Predicate::Factory.in(identifier, subquery)
|
46
45
|
else
|
47
46
|
join_pre = join_predicate(left, subquery, commons)
|
48
47
|
subquery = expand_where_clause(subquery, join_pre)
|
@@ -8,17 +8,37 @@ module Bmg
|
|
8
8
|
@predicate = predicate
|
9
9
|
end
|
10
10
|
|
11
|
+
def on_union(sexpr)
|
12
|
+
non_falsy = sexpr[2..-1].reject{|expr| falsy?(expr) }
|
13
|
+
if non_falsy.empty?
|
14
|
+
apply(sexpr.head_expr)
|
15
|
+
elsif non_falsy.size == 1
|
16
|
+
apply(non_falsy.first)
|
17
|
+
else
|
18
|
+
[sexpr[0], sexpr[1]] + non_falsy.map{|nf| apply(nf) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
11
22
|
def on_select_exp(sexpr)
|
12
|
-
pred = @predicate.rename(sexpr.desaliaser)
|
23
|
+
pred = @predicate.rename(sexpr.desaliaser(true))
|
13
24
|
if sexpr.where_clause
|
14
|
-
|
15
|
-
|
16
|
-
sexpr.with_update(:where_clause, [ :where_clause, anded ])
|
25
|
+
sexpr_p = Predicate.new(sexpr.where_clause.predicate)
|
26
|
+
sexpr.with_update(:where_clause, [ :where_clause, (sexpr_p & pred).sexpr ])
|
17
27
|
else
|
18
|
-
sexpr.with_insert(4, [ :where_clause, pred ])
|
28
|
+
sexpr.with_insert(4, [ :where_clause, pred.sexpr ])
|
19
29
|
end
|
20
30
|
end
|
21
31
|
|
32
|
+
private
|
33
|
+
|
34
|
+
def falsy?(sexpr)
|
35
|
+
return false unless sexpr.respond_to?(:predicate)
|
36
|
+
return false if sexpr.predicate.nil?
|
37
|
+
left = Predicate.new(Predicate::Grammar.sexpr(sexpr.predicate))
|
38
|
+
right = Predicate.new(Predicate::Grammar.sexpr(@predicate.sexpr))
|
39
|
+
return (left & right).contradiction?
|
40
|
+
end
|
41
|
+
|
22
42
|
end # class Where
|
23
43
|
end # class Processor
|
24
44
|
end # module Sql
|
data/lib/bmg/sql/relation.rb
CHANGED
@@ -44,6 +44,12 @@ module Bmg
|
|
44
44
|
_instance(type, builder, expr)
|
45
45
|
end
|
46
46
|
|
47
|
+
def _constants(type, cs)
|
48
|
+
expr = before_use(self.expr)
|
49
|
+
expr = Processor::Constants.new(cs, builder).call(expr)
|
50
|
+
_instance(type, builder, expr)
|
51
|
+
end
|
52
|
+
|
47
53
|
def _join(type, right, on)
|
48
54
|
if right_expr = extract_compatible_sexpr(right)
|
49
55
|
right_expr = Processor::Requalify.new(builder).call(right_expr)
|
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.13.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: 2018-05-
|
11
|
+
date: 2018-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: predicate
|
@@ -66,20 +66,6 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.3'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: roo
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '2.7'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '2.7'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: sequel
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -209,6 +195,7 @@ files:
|
|
209
195
|
- lib/bmg/sql/processor.rb
|
210
196
|
- lib/bmg/sql/processor/all.rb
|
211
197
|
- lib/bmg/sql/processor/clip.rb
|
198
|
+
- lib/bmg/sql/processor/constants.rb
|
212
199
|
- lib/bmg/sql/processor/distinct.rb
|
213
200
|
- lib/bmg/sql/processor/flatten.rb
|
214
201
|
- lib/bmg/sql/processor/from_self.rb
|
@@ -252,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
252
239
|
version: '0'
|
253
240
|
requirements: []
|
254
241
|
rubyforge_project:
|
255
|
-
rubygems_version: 2.
|
242
|
+
rubygems_version: 2.5.2
|
256
243
|
signing_key:
|
257
244
|
specification_version: 4
|
258
245
|
summary: Bmg is Alf's successor.
|