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,17 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Distinct < Processor
5
+
6
+ def on_set_quantified(sexpr)
7
+ sexpr.with_update(1, builder.distinct)
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 Distinct
15
+ end # class Processor
16
+ end # module Sql
17
+ end # module Bmg
@@ -0,0 +1,24 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Flatten < Processor
5
+
6
+ def on_with_exp(sexpr)
7
+ @subqueries = sexpr.with_spec.to_hash
8
+ apply(sexpr.select_exp)
9
+ end
10
+ attr_reader :subqueries
11
+
12
+ alias :on_select_exp :copy_and_apply
13
+ alias :on_missing :copy_and_apply
14
+
15
+ def on_table_as(sexpr)
16
+ return sexpr unless subqueries
17
+ return sexpr unless subquery = subqueries[sexpr.table_name]
18
+ [ :subquery_as, apply(subquery), sexpr.right ]
19
+ end
20
+
21
+ end # class Flatten
22
+ end # class Processor
23
+ end # module Sql
24
+ end # module Bmg
@@ -0,0 +1,29 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class FromSelf < Processor
5
+
6
+ def on_with_exp(sexpr)
7
+ q = builder.next_qualifier!
8
+ name_intro = builder.name_intro(q, sexpr.select_exp)
9
+ [ :with_exp,
10
+ sexpr.with_spec.dup.push(name_intro),
11
+ builder.select_all(sexpr.select_exp, q, q) ]
12
+ end
13
+
14
+ def on_nonjoin_exp(sexpr)
15
+ q = builder.next_qualifier!
16
+ [ :with_exp,
17
+ [:with_spec,
18
+ builder.name_intro(q, sexpr)],
19
+ builder.select_all(sexpr, q, q) ]
20
+ end
21
+ alias :on_union :on_nonjoin_exp
22
+ alias :on_except :on_nonjoin_exp
23
+ alias :on_intersect :on_nonjoin_exp
24
+ alias :on_select_exp :on_nonjoin_exp
25
+
26
+ end # class FromSelf
27
+ end # class Processor
28
+ end # module Sql
29
+ end # module Bmg
@@ -0,0 +1,80 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Join < Processor
5
+ include JoinSupport
6
+
7
+ def initialize(right, builder)
8
+ super(builder)
9
+ @right = right
10
+ end
11
+ attr_reader :right
12
+
13
+ def call(sexpr)
14
+ if unjoinable?(sexpr)
15
+ call(builder.from_self(sexpr))
16
+ elsif unjoinable?(right)
17
+ Join.new(builder.from_self(right), builder).call(sexpr)
18
+ else
19
+ super(sexpr)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def apply_join_strategy(left, right)
26
+ [ :select_exp,
27
+ join_set_quantifiers(left, right),
28
+ join_select_lists(left, right),
29
+ join_from_clauses(left, right),
30
+ join_where_clauses(left, right),
31
+ join_order_by_clauses(left, right) ].compact
32
+ end
33
+
34
+ def unjoinable?(sexpr)
35
+ sexpr.set_operator? or sexpr.limit_or_offset? or sexpr.join?
36
+ end
37
+
38
+ def join_set_quantifiers(left, right)
39
+ left_q, right_q = left.set_quantifier, right.set_quantifier
40
+ left_q == right_q ? left_q : builder.distinct
41
+ end
42
+
43
+ def join_select_lists(left, right)
44
+ left_list, right_list = left.select_list, right.select_list
45
+ list = left_list.dup
46
+ right_list.each_child do |child, index|
47
+ list << child unless left_list.knows?(child.as_name)
48
+ end
49
+ list
50
+ end
51
+
52
+ def join_from_clauses(left, right)
53
+ joincon = join_predicate(left, right)
54
+ join = if joincon.tautology?
55
+ [:cross_join, left.table_spec, right.table_spec]
56
+ else
57
+ [:inner_join, left.table_spec, right.table_spec, joincon]
58
+ end
59
+ left.from_clause.with_update(-1, join)
60
+ end
61
+
62
+ def join_where_clauses(left, right)
63
+ predicate = [ tautology, left.predicate, right.predicate ].compact
64
+ case predicate.size
65
+ when 1 then nil
66
+ when 2 then [ :where_clause, predicate.last ]
67
+ else [ :where_clause, predicate.reduce(:&) ]
68
+ end
69
+ end
70
+
71
+ def join_order_by_clauses(left, right)
72
+ order_by = [ left.order_by_clause, right.order_by_clause ].compact
73
+ return order_by.first if order_by.size <= 1
74
+ order_by.first + order_by.last.sexpr_body
75
+ end
76
+
77
+ end # class Join
78
+ end # class Processor
79
+ end # module Sql
80
+ end # module Bmg
@@ -0,0 +1,28 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ module JoinSupport
5
+
6
+ def on_main_exp(sexpr)
7
+ joined = apply_join_strategy(sexpr.select_exp, right.select_exp)
8
+ merge_with_exps(sexpr, right, joined)
9
+ end
10
+ alias :on_with_exp :on_main_exp
11
+ alias :on_select_exp :on_main_exp
12
+
13
+ private
14
+
15
+ def join_predicate(left, right, commons)
16
+ left_d, right_d = left.desaliaser, right.desaliaser
17
+ commons.to_a.inject(tautology){|cond, attr|
18
+ left_attr, right_attr = left_d[attr], right_d[attr]
19
+ left_p = Predicate::Factory.qualified_identifier(left_attr.qualifier, left_attr.as_name)
20
+ right_p = Predicate::Factory.qualified_identifier(right_attr.qualifier, right_attr.as_name)
21
+ cond &= Predicate::Factory.eq(left_p, right_p)
22
+ }
23
+ end
24
+
25
+ end # class JoinSupport
26
+ end # class Processor
27
+ end # module Sql
28
+ end # module Bmg
@@ -0,0 +1,30 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class LimitOffset < Processor
5
+
6
+ def initialize(limit, offset, builder)
7
+ super(builder)
8
+ @limit = limit
9
+ @offset = offset
10
+ end
11
+ attr_reader :limit, :offset
12
+
13
+ def on_set_operator(sexpr)
14
+ apply(builder.from_self(sexpr))
15
+ end
16
+ alias :on_union :on_set_operator
17
+ alias :on_except :on_set_operator
18
+ alias :on_intersect :on_set_operator
19
+
20
+ def on_select_exp(sexpr)
21
+ sexpr = builder.from_self(sexpr) if obc = sexpr.limit_or_offset?
22
+ limit_clause = builder.limit_clause(limit)
23
+ offset_clause = builder.offset_clause(offset)
24
+ sexpr.with_push(limit_clause, offset_clause)
25
+ end
26
+
27
+ end # class LimitOffset
28
+ end # class Processor
29
+ end # module Sql
30
+ end # module Bmg
@@ -0,0 +1,49 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Merge < Processor
5
+
6
+ def initialize(kind, all, right, builder)
7
+ super(builder)
8
+ @kind = kind
9
+ @all = all
10
+ @right = right
11
+ end
12
+
13
+ def on_with_exp(sexpr)
14
+ if @right.with_exp?
15
+ reordered = Reorder.new(sexpr.to_attr_list, builder).call(@right)
16
+ main = [ @kind, modifier, sexpr.select_exp, reordered.select_exp ]
17
+ merge_with_exps(sexpr, reordered, main)
18
+ else
19
+ [ :with_exp,
20
+ sexpr.with_spec,
21
+ apply(sexpr.last) ]
22
+ end
23
+ end
24
+
25
+ def on_nonjoin_exp(sexpr)
26
+ reordered = Reorder.new(sexpr.to_attr_list, builder).call(@right)
27
+ if @right.with_exp?
28
+ [ :with_exp,
29
+ reordered.with_spec,
30
+ [ @kind, modifier, sexpr, reordered.select_exp ] ]
31
+ else
32
+ [ @kind, modifier, sexpr, reordered ]
33
+ end
34
+ end
35
+ alias :on_union :on_nonjoin_exp
36
+ alias :on_except :on_nonjoin_exp
37
+ alias :on_intersect :on_nonjoin_exp
38
+ alias :on_select_exp :on_nonjoin_exp
39
+
40
+ private
41
+
42
+ def modifier
43
+ @all ? builder.all : builder.distinct
44
+ end
45
+
46
+ end # class Merge
47
+ end # class Processor
48
+ end # module Sql
49
+ end # module Bmg
@@ -0,0 +1,32 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class OrderBy < Processor
5
+
6
+ def initialize(ordering, builder)
7
+ super(builder)
8
+ @ordering = ordering
9
+ end
10
+ attr_reader :ordering
11
+
12
+ def on_set_operator(sexpr)
13
+ call(builder.from_self(sexpr))
14
+ end
15
+ alias :on_union :on_set_operator
16
+ alias :on_except :on_set_operator
17
+ alias :on_intersect :on_set_operator
18
+
19
+ def on_select_exp(sexpr)
20
+ if obc = sexpr.order_by_clause
21
+ sexpr = builder.from_self(sexpr)
22
+ call(sexpr)
23
+ else
24
+ needed = builder.order_by_clause(ordering, &sexpr.desaliaser)
25
+ sexpr.dup.push(needed)
26
+ end
27
+ end
28
+
29
+ end # class OrderBy
30
+ end # class Processor
31
+ end # module Sql
32
+ end # module Bmg
@@ -0,0 +1,25 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Rename < Processor
5
+
6
+ def initialize(renaming, builder)
7
+ super(builder)
8
+ @renaming = renaming
9
+ end
10
+
11
+ def on_select_list(sexpr)
12
+ sexpr.each_with_index.map{|child,index|
13
+ index == 0 ? child : apply(child)
14
+ }
15
+ end
16
+
17
+ def on_select_item(sexpr)
18
+ return sexpr unless newname = @renaming[sexpr.as_name.to_sym]
19
+ builder.select_item(sexpr.qualifier, sexpr.would_be_name, newname.to_s)
20
+ end
21
+
22
+ end # class Rename
23
+ end # class Processor
24
+ end # module Sql
25
+ end # module Bmg
@@ -0,0 +1,21 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Reorder < Processor
5
+
6
+ def initialize(attr_list, builder)
7
+ super(builder)
8
+ @indexes = Hash[attr_list.to_a.map(&:to_s).each_with_index.to_a]
9
+ end
10
+
11
+ def on_select_list(sexpr)
12
+ reordered = sexpr.sexpr_body.sort{|i1,i2|
13
+ @indexes[i1.as_name] <=> @indexes[i2.as_name]
14
+ }
15
+ reordered.unshift(:select_list)
16
+ end
17
+
18
+ end # class Reorder
19
+ end # class Processor
20
+ end # module Sql
21
+ end # module Bmg
@@ -0,0 +1,24 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Requalify < Processor
5
+
6
+ def initialize(builder)
7
+ super
8
+ @requalify = Hash.new{|h,k|
9
+ h[k] = Grammar.sexpr [:range_var_name, builder.next_qualifier!]
10
+ }
11
+ end
12
+ attr_reader :requalify
13
+
14
+ alias :on_select_exp :copy_and_apply
15
+ alias :on_missing :copy_and_apply
16
+
17
+ def on_range_var_name(sexpr)
18
+ requalify[sexpr]
19
+ end
20
+
21
+ end # class Requalify
22
+ end # class Processor
23
+ end # module Sql
24
+ end # module Bmg
@@ -0,0 +1,68 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class SemiJoin < Processor
5
+ include JoinSupport
6
+
7
+ def initialize(right, on, negate = false, builder)
8
+ super(builder)
9
+ @right = right
10
+ @on = on
11
+ @negate = negate
12
+ end
13
+ attr_reader :right, :on, :negate
14
+
15
+ def call(sexpr)
16
+ if sexpr.set_operator?
17
+ call(builder.from_self(sexpr))
18
+ elsif right.set_operator?
19
+ SemiJoin.new(builder.from_self(right), negate, builder).call(sexpr)
20
+ else
21
+ super(sexpr)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def apply_join_strategy(left, right)
28
+ predicate = build_semijoin_predicate(left, right)
29
+ expand_where_clause(left, negate ? !predicate : predicate)
30
+ end
31
+
32
+ def build_semijoin_predicate(left, right)
33
+ if right.is_table_dee?
34
+ right.where_clause.predicate
35
+ else
36
+ commons = self.on
37
+ subquery = Clip.new(commons, false, :star, builder).call(right)
38
+ subquery = Requalify.new(builder).call(subquery)
39
+ if commons.size == 0
40
+ builder.exists(subquery)
41
+ elsif commons.size == 1
42
+ identifier = left.desaliaser[commons.to_a.first]
43
+ Predicate::Factory.in(identifier, subquery)
44
+ else
45
+ join_pre = join_predicate(left, subquery, commons)
46
+ subquery = expand_where_clause(subquery, join_pre)
47
+ subquery = Star.new(builder).call(subquery)
48
+ builder.exists(subquery)
49
+ end
50
+ end
51
+ end
52
+
53
+ def expand_where_clause(sexpr, predicate)
54
+ Grammar.sexpr \
55
+ [ :select_exp,
56
+ sexpr.set_quantifier,
57
+ sexpr.select_list,
58
+ sexpr.from_clause,
59
+ [ :where_clause, (sexpr.predicate || tautology) & predicate ],
60
+ sexpr.order_by_clause,
61
+ sexpr.limit_clause,
62
+ sexpr.offset_clause ].compact
63
+ end
64
+
65
+ end # class SemiJoin
66
+ end # class Processor
67
+ end # module Sql
68
+ end # module Bmg
@@ -0,0 +1,17 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Star < Processor
5
+
6
+ def on_select_exp(sexpr)
7
+ if sexpr.from_clause
8
+ sexpr.with_update(:select_list, builder.select_star)
9
+ else
10
+ sexpr
11
+ end
12
+ end
13
+
14
+ end # class Star
15
+ end # class Processor
16
+ end # module Sql
17
+ end # module Bmg