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,68 @@
1
+ module Bmg
2
+ module Sql
3
+ module SetOperator
4
+ include Expr
5
+
6
+ def left
7
+ self[2]
8
+ end
9
+
10
+ def right
11
+ self[3]
12
+ end
13
+
14
+ def set_quantifier
15
+ self[1]
16
+ end
17
+
18
+ def with_exp?
19
+ false
20
+ end
21
+
22
+ def set_operator?
23
+ true
24
+ end
25
+
26
+ def is_table_dee?
27
+ false
28
+ end
29
+
30
+ def distinct?
31
+ set_quantifier.distinct?
32
+ end
33
+
34
+ def all?
35
+ set_quantifier.all?
36
+ end
37
+
38
+ def should_be_reused?
39
+ true
40
+ end
41
+
42
+ def order_by_clause
43
+ nil
44
+ end
45
+
46
+ def to_attr_list
47
+ self.last.to_attr_list
48
+ end
49
+
50
+ def to_sql(buffer, dialect, parenthesize = !buffer.empty?)
51
+ if parenthesize
52
+ sql_parenthesized(buffer){|b| to_sql(b, dialect, false) }
53
+ else
54
+ left.to_sql(buffer, dialect, true)
55
+ buffer << SPACE << keyword
56
+ unless distinct?
57
+ buffer << SPACE
58
+ set_quantifier.to_sql(buffer, dialect)
59
+ end
60
+ buffer << SPACE
61
+ right.to_sql(buffer, dialect, true)
62
+ buffer
63
+ end
64
+ end
65
+
66
+ end # module SetOperator
67
+ end # module Sql
68
+ end # module Bmg
@@ -0,0 +1,20 @@
1
+ module Bmg
2
+ module Sql
3
+ module SetQuantifier
4
+ include Expr
5
+
6
+ def all?
7
+ last == "all"
8
+ end
9
+
10
+ def distinct?
11
+ last == "distinct"
12
+ end
13
+
14
+ def to_sql(buffer, dialect)
15
+ buffer << self.last
16
+ end
17
+
18
+ end # module SetQuantifier
19
+ end # module Sql
20
+ end # module Bmg
@@ -0,0 +1,28 @@
1
+ module Bmg
2
+ module Sql
3
+ module SubqueryAs
4
+ include Expr
5
+
6
+ def left
7
+ self[1]
8
+ end
9
+ alias :subquery :left
10
+
11
+ def right
12
+ self[2]
13
+ end
14
+
15
+ def as_name
16
+ self[2].last
17
+ end
18
+
19
+ def to_sql(buffer, dialect)
20
+ left.to_sql(buffer, dialect)
21
+ buffer << SPACE << AS << SPACE
22
+ right.to_sql(buffer, dialect)
23
+ buffer
24
+ end
25
+
26
+ end # module SubqueryAs
27
+ end # module Sql
28
+ end # module Bmg
@@ -0,0 +1,31 @@
1
+ module Bmg
2
+ module Sql
3
+ module TableAs
4
+ include Expr
5
+
6
+ def left
7
+ self[1]
8
+ end
9
+
10
+ def right
11
+ self[2]
12
+ end
13
+
14
+ def table_name
15
+ self[1].last
16
+ end
17
+
18
+ def as_name
19
+ self[2].last
20
+ end
21
+
22
+ def to_sql(buffer, dialect)
23
+ self[1].to_sql(buffer, dialect)
24
+ buffer << SPACE << AS << SPACE
25
+ self[2].to_sql(buffer, dialect)
26
+ buffer
27
+ end
28
+
29
+ end # module TableAs
30
+ end # module Sql
31
+ end # module Bmg
@@ -0,0 +1,17 @@
1
+ module Bmg
2
+ module Sql
3
+ module TableName
4
+ include Expr
5
+
6
+ def value
7
+ last
8
+ end
9
+
10
+ def to_sql(buffer, dialect)
11
+ buffer << dialect.quote_identifier(last.to_s)
12
+ buffer
13
+ end
14
+
15
+ end # module TableName
16
+ end # module Sql
17
+ end # module Bmg
@@ -0,0 +1,14 @@
1
+ module Bmg
2
+ module Sql
3
+ module Union
4
+ include SetOperator
5
+
6
+ UNION = "UNION".freeze
7
+
8
+ def keyword
9
+ UNION
10
+ end
11
+
12
+ end # module Union
13
+ end # module Sql
14
+ end # module Bmg
@@ -0,0 +1,20 @@
1
+ module Bmg
2
+ module Sql
3
+ module WhereClause
4
+ include Expr
5
+
6
+ WHERE = "WHERE".freeze
7
+
8
+ def predicate
9
+ last
10
+ end
11
+
12
+ def to_sql(buffer, dialect)
13
+ buffer << WHERE << SPACE
14
+ predicate.to_sql(buffer, dialect)
15
+ buffer
16
+ end
17
+
18
+ end # module WhereClause
19
+ end # module Sql
20
+ end # module Bmg
@@ -0,0 +1,51 @@
1
+ module Bmg
2
+ module Sql
3
+ module WithExp
4
+ include Expr
5
+ extend Forwardable
6
+
7
+ WITH = "WITH".freeze
8
+
9
+ def with_exp?
10
+ true
11
+ end
12
+
13
+ def with_spec
14
+ self[1]
15
+ end
16
+
17
+ def select_exp
18
+ last
19
+ end
20
+ def_delegators :select_exp, :select_list,
21
+ :where_clause,
22
+ :predicate,
23
+ :from_clause,
24
+ :table_spec,
25
+ :order_by_clause,
26
+ :limit_clause,
27
+ :offset_clause,
28
+ :desaliaser,
29
+ :to_attr_list,
30
+ :to_ordering,
31
+ :all?,
32
+ :distinct?,
33
+ :set_operator?,
34
+ :limit_or_offset?,
35
+ :join?,
36
+ :should_be_reused?,
37
+ :is_table_dee?
38
+
39
+ # to_xxx
40
+
41
+ def to_sql(buffer, dialect)
42
+ buffer << WITH << SPACE
43
+ self[1].to_sql(buffer, dialect)
44
+ buffer << SPACE
45
+ self[2].to_sql(buffer, dialect, false)
46
+ buffer
47
+ end
48
+
49
+ end # module WithExp
50
+ end # module Sql
51
+ end # module Bmg
@@ -0,0 +1,24 @@
1
+ module Bmg
2
+ module Sql
3
+ module WithSpec
4
+ include Expr
5
+
6
+ def to_sql(buffer, dialect)
7
+ each_child do |child,index|
8
+ buffer << COMMA << SPACE unless index==0
9
+ child.to_sql(buffer, dialect)
10
+ end
11
+ buffer
12
+ end
13
+
14
+ def to_hash
15
+ hash = {}
16
+ each_child do |child|
17
+ hash[child.table_name.value] = child.subquery
18
+ end
19
+ hash
20
+ end
21
+
22
+ end # module WithSpec
23
+ end # module Sql
24
+ end # module Bmg
@@ -0,0 +1,85 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor < Sexpr::Rewriter
4
+ grammar Sql::Grammar
5
+
6
+ UnexpectedError = Class.new(Bmg::Error)
7
+
8
+ def initialize(builder)
9
+ @builder = builder
10
+ end
11
+ attr_reader :builder
12
+
13
+ def on_with_exp(sexpr)
14
+ applied = apply(sexpr.select_exp)
15
+ if applied.with_exp?
16
+ merge_with_exps(sexpr, applied, applied.select_exp)
17
+ else
18
+ sexpr.with_update(-1, applied)
19
+ end
20
+ end
21
+
22
+ def on_set_operator(sexpr)
23
+ sexpr.each_with_index.map{|child,index|
24
+ index <= 1 ? child : apply(child)
25
+ }
26
+ end
27
+ alias :on_union :on_set_operator
28
+ alias :on_except :on_set_operator
29
+ alias :on_intersect :on_set_operator
30
+
31
+ def on_select_exp(sexpr)
32
+ sexpr.with_update(2, apply(sexpr[2]))
33
+ end
34
+
35
+ private
36
+
37
+ def merge_with_exps(left, right, main)
38
+ if left.with_exp? and right.with_exp?
39
+ [ :with_exp,
40
+ merge_with_specs(left.with_spec, right.with_spec),
41
+ main ]
42
+ elsif left.with_exp?
43
+ left.with_update(-1, main)
44
+ elsif right.with_exp?
45
+ right.with_update(-1, main)
46
+ else
47
+ main
48
+ end
49
+ end
50
+
51
+ def merge_with_specs(left, right)
52
+ hash = left.to_hash.merge(right.to_hash){|k,v1,v2|
53
+ unless v1 == v2
54
+ msg = "Unexpected different SQL expr: "
55
+ msg << "`#{v1.inspect}` vs. `#{v2.inspect}`"
56
+ raise UnexpectedError, msg
57
+ end
58
+ v1
59
+ }
60
+ hash.map{|(k,v)| builder.name_intro(k,v) }.unshift(:with_spec)
61
+ end
62
+
63
+ def tautology
64
+ Predicate::Factory.tautology
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+ require_relative 'processor/distinct'
71
+ require_relative 'processor/all'
72
+ require_relative 'processor/clip'
73
+ require_relative 'processor/star'
74
+ require_relative 'processor/rename'
75
+ require_relative 'processor/order_by'
76
+ require_relative 'processor/limit_offset'
77
+ require_relative 'processor/from_self'
78
+ require_relative 'processor/reorder'
79
+ require_relative 'processor/merge'
80
+ require_relative 'processor/where'
81
+ require_relative 'processor/join_support'
82
+ require_relative 'processor/join'
83
+ require_relative 'processor/semi_join'
84
+ require_relative 'processor/flatten'
85
+ require_relative 'processor/requalify'
@@ -0,0 +1,17 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class All < Processor
5
+
6
+ def on_set_quantified(sexpr)
7
+ sexpr.with_update(1, builder.all)
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 All
15
+ end # class Processor
16
+ end # module Sql
17
+ end # module Bmg
@@ -0,0 +1,57 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Clip < Processor
5
+
6
+ def initialize(attributes, allbut = false, on_empty = :is_table_dee, builder)
7
+ super(builder)
8
+ @attributes = attributes
9
+ @allbut = allbut
10
+ @on_empty = on_empty
11
+ end
12
+ attr_reader :attributes, :on_empty
13
+
14
+ def allbut?
15
+ @allbut
16
+ end
17
+
18
+ def on_set_operator(sexpr)
19
+ apply(builder.from_self(sexpr))
20
+ end
21
+ alias :on_union :on_set_operator
22
+ alias :on_except :on_set_operator
23
+ alias :on_intersect :on_set_operator
24
+
25
+ def on_select_exp(sexpr)
26
+ catch(:empty){ return super(sexpr) }
27
+ send("select_#{on_empty}", sexpr)
28
+ end
29
+
30
+ def on_select_star(sexpr)
31
+ raise NotImplementedError, "Allbut on * is not supported" if allbut?
32
+ builder.select_list(attributes, builder.last_qualifier)
33
+ end
34
+
35
+ def on_select_list(sexpr)
36
+ allbut = self.allbut?
37
+ result = sexpr.select{|child|
38
+ (child == :select_list) or
39
+ attributes.include?(child.as_name.to_sym) == !allbut
40
+ }
41
+ (result.size==1) ? throw(:empty) : result
42
+ end
43
+
44
+ private
45
+
46
+ def select_is_table_dee(sexpr)
47
+ builder.select_is_table_dee(select_star(sexpr))
48
+ end
49
+
50
+ def select_star(sexpr)
51
+ All.new(builder).call(Star.new(builder).call(sexpr))
52
+ end
53
+
54
+ end # class Clip
55
+ end # class Processor
56
+ end # module Sql
57
+ end # module Bmg