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,42 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sequel
|
3
|
+
class TypeInference
|
4
|
+
|
5
|
+
def initialize(sequel_db)
|
6
|
+
@sequel_db = sequel_db
|
7
|
+
end
|
8
|
+
attr_reader :sequel_db
|
9
|
+
|
10
|
+
def call(name)
|
11
|
+
Type.new
|
12
|
+
.with_attrlist(attrlist(name))
|
13
|
+
.with_keys(keys(name))
|
14
|
+
end
|
15
|
+
|
16
|
+
def attrlist(name)
|
17
|
+
sequel_db.schema(name).map{|(k,v)| k }
|
18
|
+
end
|
19
|
+
|
20
|
+
def keys(name)
|
21
|
+
# take the indexes
|
22
|
+
indexes = sequel_db
|
23
|
+
.indexes(name)
|
24
|
+
.values
|
25
|
+
.select{|i| i[:unique] == true }
|
26
|
+
.map{|i| i[:columns] }
|
27
|
+
.sort{|a1, a2| a1.size <=> a2.size }
|
28
|
+
|
29
|
+
# take single keys as well
|
30
|
+
key = sequel_db
|
31
|
+
.schema(name)
|
32
|
+
.select{|(colname, colinfo)| colinfo[:primary_key] }
|
33
|
+
.map(&:first)
|
34
|
+
|
35
|
+
indexes.unshift(key) unless key.empty?
|
36
|
+
|
37
|
+
indexes
|
38
|
+
end
|
39
|
+
|
40
|
+
end # class TypeInference
|
41
|
+
end # module Sequel
|
42
|
+
end # module Bmg
|
data/lib/bmg/sql.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'sexpr'
|
2
|
+
module Bmg
|
3
|
+
|
4
|
+
module Sql
|
5
|
+
end
|
6
|
+
|
7
|
+
def sql(table, type = Type::ANY)
|
8
|
+
builder = Sql::Builder.new
|
9
|
+
sexpr = builder.select_star_from(table)
|
10
|
+
Sql::Relation.new(type, builder, sexpr).spied(main_spy)
|
11
|
+
end
|
12
|
+
module_function :sql
|
13
|
+
|
14
|
+
end # module Bmg
|
15
|
+
require_relative 'sql/ext/predicate'
|
16
|
+
require_relative 'sql/grammar'
|
17
|
+
require_relative 'sql/processor'
|
18
|
+
require_relative 'sql/builder'
|
19
|
+
require_relative 'sql/dialect'
|
20
|
+
require_relative 'sql/relation'
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
class Builder
|
4
|
+
|
5
|
+
DISTINCT = Grammar.sexpr([:set_quantifier, "distinct"])
|
6
|
+
ALL = Grammar.sexpr([:set_quantifier, "all"])
|
7
|
+
IS_TABLE_DEE = Grammar.sexpr([:select_list,
|
8
|
+
[:select_item,
|
9
|
+
[:literal, true],
|
10
|
+
[:column_name, "is_table_dee"]]])
|
11
|
+
|
12
|
+
def self.builder(meth)
|
13
|
+
old = instance_method(meth)
|
14
|
+
define_method(meth) do |*args, &bl|
|
15
|
+
Grammar.sexpr(old.bind(self).call(*args, &bl))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(start = 0)
|
20
|
+
@next_qualifier = (start || 0)
|
21
|
+
end
|
22
|
+
|
23
|
+
def distinct
|
24
|
+
DISTINCT
|
25
|
+
end
|
26
|
+
builder :distinct
|
27
|
+
|
28
|
+
def all
|
29
|
+
ALL
|
30
|
+
end
|
31
|
+
builder :all
|
32
|
+
|
33
|
+
def name_intro(name, sexpr)
|
34
|
+
[:name_intro, table_name(name), sexpr]
|
35
|
+
end
|
36
|
+
builder :name_intro
|
37
|
+
|
38
|
+
def select_star_from(name, qualifier = next_qualifier!)
|
39
|
+
[ :select_exp,
|
40
|
+
all,
|
41
|
+
select_star(qualifier),
|
42
|
+
from_clause(name, qualifier) ]
|
43
|
+
end
|
44
|
+
builder :select_star_from
|
45
|
+
|
46
|
+
def select_all(heading, name, qualifier = next_qualifier!)
|
47
|
+
[ :select_exp, all,
|
48
|
+
select_list(heading, qualifier),
|
49
|
+
from_clause(name, qualifier) ]
|
50
|
+
end
|
51
|
+
builder :select_all
|
52
|
+
|
53
|
+
def select_is_table_dee(subquery)
|
54
|
+
[ :select_exp, all, is_table_dee,
|
55
|
+
[:where_clause, exists(subquery)] ]
|
56
|
+
end
|
57
|
+
builder :select_is_table_dee
|
58
|
+
|
59
|
+
def is_table_dee
|
60
|
+
IS_TABLE_DEE
|
61
|
+
end
|
62
|
+
builder :is_table_dee
|
63
|
+
|
64
|
+
def select_list(attrs, qualifier)
|
65
|
+
attrs = attrs.to_attr_list if attrs.respond_to?(:to_attr_list)
|
66
|
+
attrs.map{|a| select_item(qualifier, a) }.unshift(:select_list)
|
67
|
+
end
|
68
|
+
builder :select_list
|
69
|
+
|
70
|
+
def select_item(qualifier, name, as = name)
|
71
|
+
[:select_item,
|
72
|
+
qualified_name(qualifier, name.to_s),
|
73
|
+
column_name(as.to_s)]
|
74
|
+
end
|
75
|
+
builder :select_item
|
76
|
+
|
77
|
+
def select_star(qualifier = next_qualifier!)
|
78
|
+
[:select_star, [:range_var_name, qualifier]]
|
79
|
+
end
|
80
|
+
builder :select_star
|
81
|
+
|
82
|
+
def from_clause(table, qualifier)
|
83
|
+
arg = case table
|
84
|
+
when String, Symbol then table_as(table, qualifier)
|
85
|
+
when Expr then subquery_as(table, qualifier)
|
86
|
+
else native_table_as(table, qualifier)
|
87
|
+
end
|
88
|
+
[ :from_clause, arg ]
|
89
|
+
end
|
90
|
+
builder :from_clause
|
91
|
+
|
92
|
+
def table_as(table, qualifier)
|
93
|
+
table = case table
|
94
|
+
when String, Symbol then table_name(table)
|
95
|
+
else table
|
96
|
+
end
|
97
|
+
[:table_as,
|
98
|
+
table,
|
99
|
+
range_var_name(qualifier) ]
|
100
|
+
end
|
101
|
+
builder :table_as
|
102
|
+
|
103
|
+
def subquery_as(subquery, qualifier)
|
104
|
+
[:subquery_as,
|
105
|
+
subquery,
|
106
|
+
range_var_name(qualifier) ]
|
107
|
+
end
|
108
|
+
builder :table_as
|
109
|
+
|
110
|
+
def native_table_as(table, qualifier)
|
111
|
+
[ :native_table_as,
|
112
|
+
table,
|
113
|
+
range_var_name(qualifier) ]
|
114
|
+
end
|
115
|
+
|
116
|
+
def qualified_name(qualifier, name)
|
117
|
+
[:qualified_name,
|
118
|
+
range_var_name(qualifier),
|
119
|
+
column_name(name) ]
|
120
|
+
end
|
121
|
+
builder :qualified_name
|
122
|
+
|
123
|
+
def range_var_name(qualifier)
|
124
|
+
[:range_var_name, qualifier]
|
125
|
+
end
|
126
|
+
builder :range_var_name
|
127
|
+
|
128
|
+
def column_name(name)
|
129
|
+
[:column_name, name]
|
130
|
+
end
|
131
|
+
builder :column_name
|
132
|
+
|
133
|
+
def table_name(name)
|
134
|
+
[:table_name, name]
|
135
|
+
end
|
136
|
+
builder :table_name
|
137
|
+
|
138
|
+
def exists(subquery)
|
139
|
+
Predicate::Grammar.sexpr [ :exists, subquery ]
|
140
|
+
end
|
141
|
+
|
142
|
+
def order_by_clause(ordering, &desaliaser)
|
143
|
+
ordering.to_a.map{|(name,direction)|
|
144
|
+
name = name.to_s
|
145
|
+
name = (desaliaser && desaliaser[name]) || column_name(name)
|
146
|
+
[:order_by_term, name, direction ? direction.to_s : "asc"]
|
147
|
+
}.unshift(:order_by_clause)
|
148
|
+
end
|
149
|
+
builder :order_by_clause
|
150
|
+
|
151
|
+
def limit_clause(limit)
|
152
|
+
[:limit_clause, limit]
|
153
|
+
end
|
154
|
+
builder :limit_clause
|
155
|
+
|
156
|
+
def offset_clause(limit)
|
157
|
+
[:offset_clause, limit]
|
158
|
+
end
|
159
|
+
builder :offset_clause
|
160
|
+
|
161
|
+
def from_self(sexpr)
|
162
|
+
Processor::FromSelf.new(self).call(sexpr)
|
163
|
+
end
|
164
|
+
|
165
|
+
public
|
166
|
+
|
167
|
+
def last_qualifier
|
168
|
+
"t#{@next_qualifier}"
|
169
|
+
end
|
170
|
+
|
171
|
+
def next_qualifier!
|
172
|
+
"t#{@next_qualifier += 1}"
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Predicate
|
2
|
+
Sql = ::Bmg::Sql
|
3
|
+
end
|
4
|
+
require_relative 'predicate/expr'
|
5
|
+
require_relative 'predicate/dyadic_comp'
|
6
|
+
require_relative 'predicate/nadic_bool'
|
7
|
+
require_relative 'predicate/tautology'
|
8
|
+
require_relative 'predicate/contradiction'
|
9
|
+
require_relative 'predicate/identifier'
|
10
|
+
require_relative 'predicate/qualified_identifier'
|
11
|
+
require_relative 'predicate/and'
|
12
|
+
require_relative 'predicate/or'
|
13
|
+
require_relative 'predicate/not'
|
14
|
+
require_relative 'predicate/eq'
|
15
|
+
require_relative 'predicate/neq'
|
16
|
+
require_relative 'predicate/gt'
|
17
|
+
require_relative 'predicate/gte'
|
18
|
+
require_relative 'predicate/lt'
|
19
|
+
require_relative 'predicate/lte'
|
20
|
+
require_relative 'predicate/in'
|
21
|
+
require_relative 'predicate/exists'
|
22
|
+
require_relative 'predicate/literal'
|
23
|
+
require_relative 'predicate/native'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Expr
|
3
|
+
|
4
|
+
def to_sql_literal(buffer, value)
|
5
|
+
case value
|
6
|
+
when TrueClass
|
7
|
+
buffer << Sql::Expr::TRUE
|
8
|
+
when FalseClass
|
9
|
+
buffer << Sql::Expr::FALSE
|
10
|
+
when Integer, Float
|
11
|
+
buffer << value.to_s
|
12
|
+
else
|
13
|
+
buffer << Sql::Expr::QUOTE << value.to_s << Sql::Expr::QUOTE
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Predicate
|
2
|
+
module In
|
3
|
+
|
4
|
+
def subquery?
|
5
|
+
Sql::Expr === last
|
6
|
+
end
|
7
|
+
|
8
|
+
def subquery
|
9
|
+
subquery? ? last : nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_sql(buffer, dialect)
|
13
|
+
identifier.to_sql(buffer, dialect)
|
14
|
+
buffer << Sql::Expr::SPACE << Sql::Expr::IN << Sql::Expr::SPACE
|
15
|
+
if subquery?
|
16
|
+
values.to_sql(buffer, dialect)
|
17
|
+
else
|
18
|
+
buffer << Sql::Expr::LEFT_PARENTHESE
|
19
|
+
values.each_with_index do |val,index|
|
20
|
+
buffer << Sql::Expr::COMMA << Sql::Expr::SPACE unless index==0
|
21
|
+
to_sql_literal(buffer, val)
|
22
|
+
end
|
23
|
+
buffer << Sql::Expr::RIGHT_PARENTHESE
|
24
|
+
end
|
25
|
+
buffer
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|