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,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
|