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