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