bmg 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bmg/algebra.rb +2 -26
  3. data/lib/bmg/algebra/shortcuts.rb +14 -0
  4. data/lib/bmg/operator/autowrap.rb +32 -2
  5. data/lib/bmg/operator/constants.rb +12 -0
  6. data/lib/bmg/operator/image.rb +10 -0
  7. data/lib/bmg/operator/rename.rb +8 -0
  8. data/lib/bmg/relation/spied.rb +4 -9
  9. data/lib/bmg/sequel.rb +53 -2
  10. data/lib/bmg/sequel/relation.rb +24 -19
  11. data/lib/bmg/sequel/translator.rb +153 -0
  12. data/lib/bmg/sequel/type_inference.rb +42 -0
  13. data/lib/bmg/sql.rb +20 -0
  14. data/lib/bmg/sql/builder.rb +177 -0
  15. data/lib/bmg/sql/dialect.rb +15 -0
  16. data/lib/bmg/sql/ext/predicate.rb +23 -0
  17. data/lib/bmg/sql/ext/predicate/and.rb +9 -0
  18. data/lib/bmg/sql/ext/predicate/contradiction.rb +10 -0
  19. data/lib/bmg/sql/ext/predicate/dyadic_comp.rb +12 -0
  20. data/lib/bmg/sql/ext/predicate/eq.rb +9 -0
  21. data/lib/bmg/sql/ext/predicate/exists.rb +12 -0
  22. data/lib/bmg/sql/ext/predicate/expr.rb +18 -0
  23. data/lib/bmg/sql/ext/predicate/gt.rb +9 -0
  24. data/lib/bmg/sql/ext/predicate/gte.rb +9 -0
  25. data/lib/bmg/sql/ext/predicate/identifier.rb +10 -0
  26. data/lib/bmg/sql/ext/predicate/in.rb +29 -0
  27. data/lib/bmg/sql/ext/predicate/literal.rb +10 -0
  28. data/lib/bmg/sql/ext/predicate/lt.rb +9 -0
  29. data/lib/bmg/sql/ext/predicate/lte.rb +9 -0
  30. data/lib/bmg/sql/ext/predicate/nadic_bool.rb +16 -0
  31. data/lib/bmg/sql/ext/predicate/native.rb +9 -0
  32. data/lib/bmg/sql/ext/predicate/neq.rb +9 -0
  33. data/lib/bmg/sql/ext/predicate/not.rb +12 -0
  34. data/lib/bmg/sql/ext/predicate/or.rb +9 -0
  35. data/lib/bmg/sql/ext/predicate/qualified_identifier.rb +12 -0
  36. data/lib/bmg/sql/ext/predicate/tautology.rb +10 -0
  37. data/lib/bmg/sql/grammar.rb +45 -0
  38. data/lib/bmg/sql/grammar.sexp.yml +96 -0
  39. data/lib/bmg/sql/nodes/column_name.rb +25 -0
  40. data/lib/bmg/sql/nodes/cross_join.rb +28 -0
  41. data/lib/bmg/sql/nodes/except.rb +14 -0
  42. data/lib/bmg/sql/nodes/expr.rb +94 -0
  43. data/lib/bmg/sql/nodes/from_clause.rb +24 -0
  44. data/lib/bmg/sql/nodes/inner_join.rb +37 -0
  45. data/lib/bmg/sql/nodes/intersect.rb +14 -0
  46. data/lib/bmg/sql/nodes/limit_clause.rb +19 -0
  47. data/lib/bmg/sql/nodes/literal.rb +18 -0
  48. data/lib/bmg/sql/nodes/name_intro.rb +23 -0
  49. data/lib/bmg/sql/nodes/native_table_as.rb +31 -0
  50. data/lib/bmg/sql/nodes/offset_clause.rb +19 -0
  51. data/lib/bmg/sql/nodes/order_by_clause.rb +25 -0
  52. data/lib/bmg/sql/nodes/order_by_term.rb +30 -0
  53. data/lib/bmg/sql/nodes/qualified_name.rb +32 -0
  54. data/lib/bmg/sql/nodes/range_var_name.rb +17 -0
  55. data/lib/bmg/sql/nodes/select_exp.rb +109 -0
  56. data/lib/bmg/sql/nodes/select_item.rb +37 -0
  57. data/lib/bmg/sql/nodes/select_list.rb +35 -0
  58. data/lib/bmg/sql/nodes/select_star.rb +22 -0
  59. data/lib/bmg/sql/nodes/set_operator.rb +68 -0
  60. data/lib/bmg/sql/nodes/set_quantifier.rb +20 -0
  61. data/lib/bmg/sql/nodes/subquery_as.rb +28 -0
  62. data/lib/bmg/sql/nodes/table_as.rb +31 -0
  63. data/lib/bmg/sql/nodes/table_name.rb +17 -0
  64. data/lib/bmg/sql/nodes/union.rb +14 -0
  65. data/lib/bmg/sql/nodes/where_clause.rb +20 -0
  66. data/lib/bmg/sql/nodes/with_exp.rb +51 -0
  67. data/lib/bmg/sql/nodes/with_spec.rb +24 -0
  68. data/lib/bmg/sql/processor.rb +85 -0
  69. data/lib/bmg/sql/processor/all.rb +17 -0
  70. data/lib/bmg/sql/processor/clip.rb +57 -0
  71. data/lib/bmg/sql/processor/distinct.rb +17 -0
  72. data/lib/bmg/sql/processor/flatten.rb +24 -0
  73. data/lib/bmg/sql/processor/from_self.rb +29 -0
  74. data/lib/bmg/sql/processor/join.rb +80 -0
  75. data/lib/bmg/sql/processor/join_support.rb +28 -0
  76. data/lib/bmg/sql/processor/limit_offset.rb +30 -0
  77. data/lib/bmg/sql/processor/merge.rb +49 -0
  78. data/lib/bmg/sql/processor/order_by.rb +32 -0
  79. data/lib/bmg/sql/processor/rename.rb +25 -0
  80. data/lib/bmg/sql/processor/reorder.rb +21 -0
  81. data/lib/bmg/sql/processor/requalify.rb +24 -0
  82. data/lib/bmg/sql/processor/semi_join.rb +68 -0
  83. data/lib/bmg/sql/processor/star.rb +17 -0
  84. data/lib/bmg/sql/processor/where.rb +25 -0
  85. data/lib/bmg/sql/relation.rb +141 -0
  86. data/lib/bmg/sql/version.rb +16 -0
  87. data/lib/bmg/support.rb +1 -0
  88. data/lib/bmg/support/keys.rb +59 -0
  89. data/lib/bmg/type.rb +95 -14
  90. data/lib/bmg/version.rb +2 -2
  91. data/tasks/test.rake +9 -2
  92. 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
@@ -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,15 @@
1
+ module Bmg
2
+ module Sql
3
+ class Dialect
4
+
5
+ def self.default
6
+ Dialect.new
7
+ end
8
+
9
+ def quote_identifier(identifier)
10
+ %Q{"#{identifier}"}
11
+ end
12
+
13
+ end # class Dialect
14
+ end # module Sql
15
+ end # module Bmg
@@ -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,9 @@
1
+ class Predicate
2
+ module And
3
+
4
+ def to_sql_operator
5
+ Sql::Expr::AND
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class Predicate
2
+ module Contradiction
3
+
4
+ def to_sql(buffer, dialect)
5
+ buffer << Sql::Expr::FALSE
6
+ buffer
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ class Predicate
2
+ module DyadicComp
3
+
4
+ def to_sql(buffer, dialect)
5
+ left.to_sql(buffer, dialect)
6
+ buffer << Sql::Expr::SPACE << to_sql_operator << Sql::Expr::SPACE
7
+ right.to_sql(buffer, dialect)
8
+ buffer
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ class Predicate
2
+ module Eq
3
+
4
+ def to_sql_operator
5
+ Sql::Expr::EQUAL
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class Predicate
2
+ module Exists
3
+ include Expr
4
+
5
+ def to_sql(buffer, dialect)
6
+ buffer << Sql::Expr::EXISTS
7
+ last.to_sql(buffer, dialect)
8
+ buffer
9
+ end
10
+
11
+ end
12
+ end
@@ -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,9 @@
1
+ class Predicate
2
+ module Gt
3
+
4
+ def to_sql_operator
5
+ Sql::Expr::GREATER
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Predicate
2
+ module Gte
3
+
4
+ def to_sql_operator
5
+ Sql::Expr::GREATER_OR_EQUAL
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class Predicate
2
+ module Identifier
3
+
4
+ def to_sql(buffer, dialect)
5
+ buffer << dialect.quote_identifier(name)
6
+ buffer
7
+ end
8
+
9
+ end
10
+ 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
@@ -0,0 +1,10 @@
1
+ class Predicate
2
+ module Literal
3
+
4
+ def to_sql(buffer, dialect)
5
+ to_sql_literal(buffer, value)
6
+ buffer
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class Predicate
2
+ module Lt
3
+
4
+ def to_sql_operator
5
+ Sql::Expr::LESS
6
+ end
7
+
8
+ end
9
+ end