bmg 0.9.1 → 0.10.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 -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
|