bmg 0.9.1 → 0.10.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 -26
- data/lib/bmg/algebra/shortcuts.rb +14 -0
- data/lib/bmg/operator/autowrap.rb +32 -2
- data/lib/bmg/operator/constants.rb +12 -0
- data/lib/bmg/operator/image.rb +10 -0
- data/lib/bmg/operator/rename.rb +8 -0
- data/lib/bmg/relation/spied.rb +4 -9
- data/lib/bmg/sequel.rb +53 -2
- data/lib/bmg/sequel/relation.rb +24 -19
- data/lib/bmg/sequel/translator.rb +153 -0
- data/lib/bmg/sequel/type_inference.rb +42 -0
- data/lib/bmg/sql.rb +20 -0
- data/lib/bmg/sql/builder.rb +177 -0
- data/lib/bmg/sql/dialect.rb +15 -0
- data/lib/bmg/sql/ext/predicate.rb +23 -0
- data/lib/bmg/sql/ext/predicate/and.rb +9 -0
- data/lib/bmg/sql/ext/predicate/contradiction.rb +10 -0
- data/lib/bmg/sql/ext/predicate/dyadic_comp.rb +12 -0
- data/lib/bmg/sql/ext/predicate/eq.rb +9 -0
- data/lib/bmg/sql/ext/predicate/exists.rb +12 -0
- data/lib/bmg/sql/ext/predicate/expr.rb +18 -0
- data/lib/bmg/sql/ext/predicate/gt.rb +9 -0
- data/lib/bmg/sql/ext/predicate/gte.rb +9 -0
- data/lib/bmg/sql/ext/predicate/identifier.rb +10 -0
- data/lib/bmg/sql/ext/predicate/in.rb +29 -0
- data/lib/bmg/sql/ext/predicate/literal.rb +10 -0
- data/lib/bmg/sql/ext/predicate/lt.rb +9 -0
- data/lib/bmg/sql/ext/predicate/lte.rb +9 -0
- data/lib/bmg/sql/ext/predicate/nadic_bool.rb +16 -0
- data/lib/bmg/sql/ext/predicate/native.rb +9 -0
- data/lib/bmg/sql/ext/predicate/neq.rb +9 -0
- data/lib/bmg/sql/ext/predicate/not.rb +12 -0
- data/lib/bmg/sql/ext/predicate/or.rb +9 -0
- data/lib/bmg/sql/ext/predicate/qualified_identifier.rb +12 -0
- data/lib/bmg/sql/ext/predicate/tautology.rb +10 -0
- data/lib/bmg/sql/grammar.rb +45 -0
- data/lib/bmg/sql/grammar.sexp.yml +96 -0
- data/lib/bmg/sql/nodes/column_name.rb +25 -0
- data/lib/bmg/sql/nodes/cross_join.rb +28 -0
- data/lib/bmg/sql/nodes/except.rb +14 -0
- data/lib/bmg/sql/nodes/expr.rb +94 -0
- data/lib/bmg/sql/nodes/from_clause.rb +24 -0
- data/lib/bmg/sql/nodes/inner_join.rb +37 -0
- data/lib/bmg/sql/nodes/intersect.rb +14 -0
- data/lib/bmg/sql/nodes/limit_clause.rb +19 -0
- data/lib/bmg/sql/nodes/literal.rb +18 -0
- data/lib/bmg/sql/nodes/name_intro.rb +23 -0
- data/lib/bmg/sql/nodes/native_table_as.rb +31 -0
- data/lib/bmg/sql/nodes/offset_clause.rb +19 -0
- data/lib/bmg/sql/nodes/order_by_clause.rb +25 -0
- data/lib/bmg/sql/nodes/order_by_term.rb +30 -0
- data/lib/bmg/sql/nodes/qualified_name.rb +32 -0
- data/lib/bmg/sql/nodes/range_var_name.rb +17 -0
- data/lib/bmg/sql/nodes/select_exp.rb +109 -0
- data/lib/bmg/sql/nodes/select_item.rb +37 -0
- data/lib/bmg/sql/nodes/select_list.rb +35 -0
- data/lib/bmg/sql/nodes/select_star.rb +22 -0
- data/lib/bmg/sql/nodes/set_operator.rb +68 -0
- data/lib/bmg/sql/nodes/set_quantifier.rb +20 -0
- data/lib/bmg/sql/nodes/subquery_as.rb +28 -0
- data/lib/bmg/sql/nodes/table_as.rb +31 -0
- data/lib/bmg/sql/nodes/table_name.rb +17 -0
- data/lib/bmg/sql/nodes/union.rb +14 -0
- data/lib/bmg/sql/nodes/where_clause.rb +20 -0
- data/lib/bmg/sql/nodes/with_exp.rb +51 -0
- data/lib/bmg/sql/nodes/with_spec.rb +24 -0
- data/lib/bmg/sql/processor.rb +85 -0
- data/lib/bmg/sql/processor/all.rb +17 -0
- data/lib/bmg/sql/processor/clip.rb +57 -0
- data/lib/bmg/sql/processor/distinct.rb +17 -0
- data/lib/bmg/sql/processor/flatten.rb +24 -0
- data/lib/bmg/sql/processor/from_self.rb +29 -0
- data/lib/bmg/sql/processor/join.rb +80 -0
- data/lib/bmg/sql/processor/join_support.rb +28 -0
- data/lib/bmg/sql/processor/limit_offset.rb +30 -0
- data/lib/bmg/sql/processor/merge.rb +49 -0
- data/lib/bmg/sql/processor/order_by.rb +32 -0
- data/lib/bmg/sql/processor/rename.rb +25 -0
- data/lib/bmg/sql/processor/reorder.rb +21 -0
- data/lib/bmg/sql/processor/requalify.rb +24 -0
- data/lib/bmg/sql/processor/semi_join.rb +68 -0
- data/lib/bmg/sql/processor/star.rb +17 -0
- data/lib/bmg/sql/processor/where.rb +25 -0
- data/lib/bmg/sql/relation.rb +141 -0
- data/lib/bmg/sql/version.rb +16 -0
- data/lib/bmg/support.rb +1 -0
- data/lib/bmg/support/keys.rb +59 -0
- data/lib/bmg/type.rb +95 -14
- data/lib/bmg/version.rb +2 -2
- data/tasks/test.rake +9 -2
- metadata +97 -5
@@ -0,0 +1,68 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module SetOperator
|
4
|
+
include Expr
|
5
|
+
|
6
|
+
def left
|
7
|
+
self[2]
|
8
|
+
end
|
9
|
+
|
10
|
+
def right
|
11
|
+
self[3]
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_quantifier
|
15
|
+
self[1]
|
16
|
+
end
|
17
|
+
|
18
|
+
def with_exp?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_operator?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_table_dee?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def distinct?
|
31
|
+
set_quantifier.distinct?
|
32
|
+
end
|
33
|
+
|
34
|
+
def all?
|
35
|
+
set_quantifier.all?
|
36
|
+
end
|
37
|
+
|
38
|
+
def should_be_reused?
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
def order_by_clause
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_attr_list
|
47
|
+
self.last.to_attr_list
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_sql(buffer, dialect, parenthesize = !buffer.empty?)
|
51
|
+
if parenthesize
|
52
|
+
sql_parenthesized(buffer){|b| to_sql(b, dialect, false) }
|
53
|
+
else
|
54
|
+
left.to_sql(buffer, dialect, true)
|
55
|
+
buffer << SPACE << keyword
|
56
|
+
unless distinct?
|
57
|
+
buffer << SPACE
|
58
|
+
set_quantifier.to_sql(buffer, dialect)
|
59
|
+
end
|
60
|
+
buffer << SPACE
|
61
|
+
right.to_sql(buffer, dialect, true)
|
62
|
+
buffer
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end # module SetOperator
|
67
|
+
end # module Sql
|
68
|
+
end # module Bmg
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module SetQuantifier
|
4
|
+
include Expr
|
5
|
+
|
6
|
+
def all?
|
7
|
+
last == "all"
|
8
|
+
end
|
9
|
+
|
10
|
+
def distinct?
|
11
|
+
last == "distinct"
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_sql(buffer, dialect)
|
15
|
+
buffer << self.last
|
16
|
+
end
|
17
|
+
|
18
|
+
end # module SetQuantifier
|
19
|
+
end # module Sql
|
20
|
+
end # module Bmg
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module SubqueryAs
|
4
|
+
include Expr
|
5
|
+
|
6
|
+
def left
|
7
|
+
self[1]
|
8
|
+
end
|
9
|
+
alias :subquery :left
|
10
|
+
|
11
|
+
def right
|
12
|
+
self[2]
|
13
|
+
end
|
14
|
+
|
15
|
+
def as_name
|
16
|
+
self[2].last
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_sql(buffer, dialect)
|
20
|
+
left.to_sql(buffer, dialect)
|
21
|
+
buffer << SPACE << AS << SPACE
|
22
|
+
right.to_sql(buffer, dialect)
|
23
|
+
buffer
|
24
|
+
end
|
25
|
+
|
26
|
+
end # module SubqueryAs
|
27
|
+
end # module Sql
|
28
|
+
end # module Bmg
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module TableAs
|
4
|
+
include Expr
|
5
|
+
|
6
|
+
def left
|
7
|
+
self[1]
|
8
|
+
end
|
9
|
+
|
10
|
+
def right
|
11
|
+
self[2]
|
12
|
+
end
|
13
|
+
|
14
|
+
def table_name
|
15
|
+
self[1].last
|
16
|
+
end
|
17
|
+
|
18
|
+
def as_name
|
19
|
+
self[2].last
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_sql(buffer, dialect)
|
23
|
+
self[1].to_sql(buffer, dialect)
|
24
|
+
buffer << SPACE << AS << SPACE
|
25
|
+
self[2].to_sql(buffer, dialect)
|
26
|
+
buffer
|
27
|
+
end
|
28
|
+
|
29
|
+
end # module TableAs
|
30
|
+
end # module Sql
|
31
|
+
end # module Bmg
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module TableName
|
4
|
+
include Expr
|
5
|
+
|
6
|
+
def value
|
7
|
+
last
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_sql(buffer, dialect)
|
11
|
+
buffer << dialect.quote_identifier(last.to_s)
|
12
|
+
buffer
|
13
|
+
end
|
14
|
+
|
15
|
+
end # module TableName
|
16
|
+
end # module Sql
|
17
|
+
end # module Bmg
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module WhereClause
|
4
|
+
include Expr
|
5
|
+
|
6
|
+
WHERE = "WHERE".freeze
|
7
|
+
|
8
|
+
def predicate
|
9
|
+
last
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_sql(buffer, dialect)
|
13
|
+
buffer << WHERE << SPACE
|
14
|
+
predicate.to_sql(buffer, dialect)
|
15
|
+
buffer
|
16
|
+
end
|
17
|
+
|
18
|
+
end # module WhereClause
|
19
|
+
end # module Sql
|
20
|
+
end # module Bmg
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module WithExp
|
4
|
+
include Expr
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
WITH = "WITH".freeze
|
8
|
+
|
9
|
+
def with_exp?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_spec
|
14
|
+
self[1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def select_exp
|
18
|
+
last
|
19
|
+
end
|
20
|
+
def_delegators :select_exp, :select_list,
|
21
|
+
:where_clause,
|
22
|
+
:predicate,
|
23
|
+
:from_clause,
|
24
|
+
:table_spec,
|
25
|
+
:order_by_clause,
|
26
|
+
:limit_clause,
|
27
|
+
:offset_clause,
|
28
|
+
:desaliaser,
|
29
|
+
:to_attr_list,
|
30
|
+
:to_ordering,
|
31
|
+
:all?,
|
32
|
+
:distinct?,
|
33
|
+
:set_operator?,
|
34
|
+
:limit_or_offset?,
|
35
|
+
:join?,
|
36
|
+
:should_be_reused?,
|
37
|
+
:is_table_dee?
|
38
|
+
|
39
|
+
# to_xxx
|
40
|
+
|
41
|
+
def to_sql(buffer, dialect)
|
42
|
+
buffer << WITH << SPACE
|
43
|
+
self[1].to_sql(buffer, dialect)
|
44
|
+
buffer << SPACE
|
45
|
+
self[2].to_sql(buffer, dialect, false)
|
46
|
+
buffer
|
47
|
+
end
|
48
|
+
|
49
|
+
end # module WithExp
|
50
|
+
end # module Sql
|
51
|
+
end # module Bmg
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
module WithSpec
|
4
|
+
include Expr
|
5
|
+
|
6
|
+
def to_sql(buffer, dialect)
|
7
|
+
each_child do |child,index|
|
8
|
+
buffer << COMMA << SPACE unless index==0
|
9
|
+
child.to_sql(buffer, dialect)
|
10
|
+
end
|
11
|
+
buffer
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
hash = {}
|
16
|
+
each_child do |child|
|
17
|
+
hash[child.table_name.value] = child.subquery
|
18
|
+
end
|
19
|
+
hash
|
20
|
+
end
|
21
|
+
|
22
|
+
end # module WithSpec
|
23
|
+
end # module Sql
|
24
|
+
end # module Bmg
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
class Processor < Sexpr::Rewriter
|
4
|
+
grammar Sql::Grammar
|
5
|
+
|
6
|
+
UnexpectedError = Class.new(Bmg::Error)
|
7
|
+
|
8
|
+
def initialize(builder)
|
9
|
+
@builder = builder
|
10
|
+
end
|
11
|
+
attr_reader :builder
|
12
|
+
|
13
|
+
def on_with_exp(sexpr)
|
14
|
+
applied = apply(sexpr.select_exp)
|
15
|
+
if applied.with_exp?
|
16
|
+
merge_with_exps(sexpr, applied, applied.select_exp)
|
17
|
+
else
|
18
|
+
sexpr.with_update(-1, applied)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_set_operator(sexpr)
|
23
|
+
sexpr.each_with_index.map{|child,index|
|
24
|
+
index <= 1 ? child : apply(child)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
alias :on_union :on_set_operator
|
28
|
+
alias :on_except :on_set_operator
|
29
|
+
alias :on_intersect :on_set_operator
|
30
|
+
|
31
|
+
def on_select_exp(sexpr)
|
32
|
+
sexpr.with_update(2, apply(sexpr[2]))
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def merge_with_exps(left, right, main)
|
38
|
+
if left.with_exp? and right.with_exp?
|
39
|
+
[ :with_exp,
|
40
|
+
merge_with_specs(left.with_spec, right.with_spec),
|
41
|
+
main ]
|
42
|
+
elsif left.with_exp?
|
43
|
+
left.with_update(-1, main)
|
44
|
+
elsif right.with_exp?
|
45
|
+
right.with_update(-1, main)
|
46
|
+
else
|
47
|
+
main
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def merge_with_specs(left, right)
|
52
|
+
hash = left.to_hash.merge(right.to_hash){|k,v1,v2|
|
53
|
+
unless v1 == v2
|
54
|
+
msg = "Unexpected different SQL expr: "
|
55
|
+
msg << "`#{v1.inspect}` vs. `#{v2.inspect}`"
|
56
|
+
raise UnexpectedError, msg
|
57
|
+
end
|
58
|
+
v1
|
59
|
+
}
|
60
|
+
hash.map{|(k,v)| builder.name_intro(k,v) }.unshift(:with_spec)
|
61
|
+
end
|
62
|
+
|
63
|
+
def tautology
|
64
|
+
Predicate::Factory.tautology
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
require_relative 'processor/distinct'
|
71
|
+
require_relative 'processor/all'
|
72
|
+
require_relative 'processor/clip'
|
73
|
+
require_relative 'processor/star'
|
74
|
+
require_relative 'processor/rename'
|
75
|
+
require_relative 'processor/order_by'
|
76
|
+
require_relative 'processor/limit_offset'
|
77
|
+
require_relative 'processor/from_self'
|
78
|
+
require_relative 'processor/reorder'
|
79
|
+
require_relative 'processor/merge'
|
80
|
+
require_relative 'processor/where'
|
81
|
+
require_relative 'processor/join_support'
|
82
|
+
require_relative 'processor/join'
|
83
|
+
require_relative 'processor/semi_join'
|
84
|
+
require_relative 'processor/flatten'
|
85
|
+
require_relative 'processor/requalify'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
class Processor
|
4
|
+
class All < Processor
|
5
|
+
|
6
|
+
def on_set_quantified(sexpr)
|
7
|
+
sexpr.with_update(1, builder.all)
|
8
|
+
end
|
9
|
+
alias :on_union :on_set_quantified
|
10
|
+
alias :on_except :on_set_quantified
|
11
|
+
alias :on_intersect :on_set_quantified
|
12
|
+
alias :on_select_exp :on_set_quantified
|
13
|
+
|
14
|
+
end # class All
|
15
|
+
end # class Processor
|
16
|
+
end # module Sql
|
17
|
+
end # module Bmg
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
class Processor
|
4
|
+
class Clip < Processor
|
5
|
+
|
6
|
+
def initialize(attributes, allbut = false, on_empty = :is_table_dee, builder)
|
7
|
+
super(builder)
|
8
|
+
@attributes = attributes
|
9
|
+
@allbut = allbut
|
10
|
+
@on_empty = on_empty
|
11
|
+
end
|
12
|
+
attr_reader :attributes, :on_empty
|
13
|
+
|
14
|
+
def allbut?
|
15
|
+
@allbut
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_set_operator(sexpr)
|
19
|
+
apply(builder.from_self(sexpr))
|
20
|
+
end
|
21
|
+
alias :on_union :on_set_operator
|
22
|
+
alias :on_except :on_set_operator
|
23
|
+
alias :on_intersect :on_set_operator
|
24
|
+
|
25
|
+
def on_select_exp(sexpr)
|
26
|
+
catch(:empty){ return super(sexpr) }
|
27
|
+
send("select_#{on_empty}", sexpr)
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_select_star(sexpr)
|
31
|
+
raise NotImplementedError, "Allbut on * is not supported" if allbut?
|
32
|
+
builder.select_list(attributes, builder.last_qualifier)
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_select_list(sexpr)
|
36
|
+
allbut = self.allbut?
|
37
|
+
result = sexpr.select{|child|
|
38
|
+
(child == :select_list) or
|
39
|
+
attributes.include?(child.as_name.to_sym) == !allbut
|
40
|
+
}
|
41
|
+
(result.size==1) ? throw(:empty) : result
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def select_is_table_dee(sexpr)
|
47
|
+
builder.select_is_table_dee(select_star(sexpr))
|
48
|
+
end
|
49
|
+
|
50
|
+
def select_star(sexpr)
|
51
|
+
All.new(builder).call(Star.new(builder).call(sexpr))
|
52
|
+
end
|
53
|
+
|
54
|
+
end # class Clip
|
55
|
+
end # class Processor
|
56
|
+
end # module Sql
|
57
|
+
end # module Bmg
|