alf-sql 0.15.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 (121) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +38 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +12 -0
  6. data/README.md +52 -0
  7. data/Rakefile +11 -0
  8. data/lib/alf-sql.rb +1 -0
  9. data/lib/alf/algebra/operand.rb +18 -0
  10. data/lib/alf/predicate/nodes.rb +20 -0
  11. data/lib/alf/predicate/nodes/and.rb +11 -0
  12. data/lib/alf/predicate/nodes/contradiction.rb +12 -0
  13. data/lib/alf/predicate/nodes/dyadic_comp.rb +14 -0
  14. data/lib/alf/predicate/nodes/eq.rb +11 -0
  15. data/lib/alf/predicate/nodes/exists.rb +14 -0
  16. data/lib/alf/predicate/nodes/expr.rb +20 -0
  17. data/lib/alf/predicate/nodes/gt.rb +11 -0
  18. data/lib/alf/predicate/nodes/gte.rb +11 -0
  19. data/lib/alf/predicate/nodes/identifier.rb +12 -0
  20. data/lib/alf/predicate/nodes/in.rb +31 -0
  21. data/lib/alf/predicate/nodes/literal.rb +12 -0
  22. data/lib/alf/predicate/nodes/lt.rb +11 -0
  23. data/lib/alf/predicate/nodes/lte.rb +11 -0
  24. data/lib/alf/predicate/nodes/nadic_bool.rb +18 -0
  25. data/lib/alf/predicate/nodes/native.rb +11 -0
  26. data/lib/alf/predicate/nodes/neq.rb +11 -0
  27. data/lib/alf/predicate/nodes/not.rb +14 -0
  28. data/lib/alf/predicate/nodes/or.rb +11 -0
  29. data/lib/alf/predicate/nodes/qualified_identifier.rb +12 -0
  30. data/lib/alf/predicate/nodes/tautology.rb +12 -0
  31. data/lib/alf/sql.rb +15 -0
  32. data/lib/alf/sql/builder.rb +152 -0
  33. data/lib/alf/sql/cog.rb +32 -0
  34. data/lib/alf/sql/compiler.rb +137 -0
  35. data/lib/alf/sql/grammar.rb +44 -0
  36. data/lib/alf/sql/grammar.sexp.yml +92 -0
  37. data/lib/alf/sql/loader.rb +2 -0
  38. data/lib/alf/sql/nodes/column_name.rb +25 -0
  39. data/lib/alf/sql/nodes/cross_join.rb +28 -0
  40. data/lib/alf/sql/nodes/except.rb +14 -0
  41. data/lib/alf/sql/nodes/expr.rb +90 -0
  42. data/lib/alf/sql/nodes/from_clause.rb +24 -0
  43. data/lib/alf/sql/nodes/inner_join.rb +37 -0
  44. data/lib/alf/sql/nodes/intersect.rb +14 -0
  45. data/lib/alf/sql/nodes/limit_clause.rb +19 -0
  46. data/lib/alf/sql/nodes/literal.rb +18 -0
  47. data/lib/alf/sql/nodes/name_intro.rb +23 -0
  48. data/lib/alf/sql/nodes/offset_clause.rb +19 -0
  49. data/lib/alf/sql/nodes/order_by_clause.rb +25 -0
  50. data/lib/alf/sql/nodes/order_by_term.rb +30 -0
  51. data/lib/alf/sql/nodes/qualified_name.rb +32 -0
  52. data/lib/alf/sql/nodes/range_var_name.rb +17 -0
  53. data/lib/alf/sql/nodes/select_exp.rb +101 -0
  54. data/lib/alf/sql/nodes/select_item.rb +37 -0
  55. data/lib/alf/sql/nodes/select_list.rb +31 -0
  56. data/lib/alf/sql/nodes/select_star.rb +15 -0
  57. data/lib/alf/sql/nodes/set_operator.rb +64 -0
  58. data/lib/alf/sql/nodes/set_quantifier.rb +20 -0
  59. data/lib/alf/sql/nodes/subquery_as.rb +28 -0
  60. data/lib/alf/sql/nodes/table_as.rb +31 -0
  61. data/lib/alf/sql/nodes/table_name.rb +17 -0
  62. data/lib/alf/sql/nodes/union.rb +14 -0
  63. data/lib/alf/sql/nodes/where_clause.rb +20 -0
  64. data/lib/alf/sql/nodes/with_exp.rb +50 -0
  65. data/lib/alf/sql/nodes/with_spec.rb +24 -0
  66. data/lib/alf/sql/processor.rb +85 -0
  67. data/lib/alf/sql/processor/all.rb +17 -0
  68. data/lib/alf/sql/processor/clip.rb +39 -0
  69. data/lib/alf/sql/processor/distinct.rb +17 -0
  70. data/lib/alf/sql/processor/flatten.rb +24 -0
  71. data/lib/alf/sql/processor/from_self.rb +29 -0
  72. data/lib/alf/sql/processor/join.rb +80 -0
  73. data/lib/alf/sql/processor/join_support.rb +27 -0
  74. data/lib/alf/sql/processor/limit_offset.rb +30 -0
  75. data/lib/alf/sql/processor/merge.rb +42 -0
  76. data/lib/alf/sql/processor/order_by.rb +32 -0
  77. data/lib/alf/sql/processor/rename.rb +25 -0
  78. data/lib/alf/sql/processor/reorder.rb +21 -0
  79. data/lib/alf/sql/processor/requalify.rb +24 -0
  80. data/lib/alf/sql/processor/semi_join.rb +57 -0
  81. data/lib/alf/sql/processor/star.rb +17 -0
  82. data/lib/alf/sql/processor/where.rb +25 -0
  83. data/lib/alf/sql/version.rb +16 -0
  84. data/spec/algebra/operand/test_to_sql.rb +32 -0
  85. data/spec/builder/test_order_by_clause.rb +44 -0
  86. data/spec/helpers/ast.rb +242 -0
  87. data/spec/helpers/compiler.rb +23 -0
  88. data/spec/nodes/column_name/test_as_name.rb +14 -0
  89. data/spec/nodes/column_name/test_qualifier.rb +14 -0
  90. data/spec/nodes/order_by_clause/test_to_ordering.rb +30 -0
  91. data/spec/nodes/order_by_term/test_as_name.rb +22 -0
  92. data/spec/nodes/order_by_term/test_direction.rb +22 -0
  93. data/spec/nodes/order_by_term/test_qualifier.rb +22 -0
  94. data/spec/nodes/select_exp/test_order_by_clause.rb +22 -0
  95. data/spec/nodes/select_item/test_as_name.rb +22 -0
  96. data/spec/predicate/nodes/exists/test_not.rb +20 -0
  97. data/spec/processor/clip/test_on_select_exp.rb +32 -0
  98. data/spec/processor/clip/test_on_select_list.rb +24 -0
  99. data/spec/processor/distinct/test_on_set_quantified.rb +31 -0
  100. data/spec/processor/from_self/test_on_nonjoin_exp.rb +60 -0
  101. data/spec/processor/from_self/test_on_with_exp.rb +22 -0
  102. data/spec/processor/merge/test_on_select_exp.rb +73 -0
  103. data/spec/processor/merge/test_on_with_exp.rb +56 -0
  104. data/spec/processor/order_by/test_on_select_exp.rb +24 -0
  105. data/spec/processor/rename/test_on_select_item.rb +30 -0
  106. data/spec/processor/rename/test_on_select_list.rb +22 -0
  107. data/spec/processor/reorder/test_on_select_list.rb +22 -0
  108. data/spec/processor/requalify/test_on_select_exp.rb +24 -0
  109. data/spec/processor/star/test_on_select_exp.rb +24 -0
  110. data/spec/processor/test_clip.rb +24 -0
  111. data/spec/processor/test_distinct.rb +24 -0
  112. data/spec/processor/test_on_select_exp.rb +28 -0
  113. data/spec/processor/test_on_set_operator.rb +28 -0
  114. data/spec/processor/test_rename.rb +24 -0
  115. data/spec/shared/compiled_examples.rb +13 -0
  116. data/spec/spec_helper.rb +14 -0
  117. data/spec/test_sql.rb +10 -0
  118. data/tasks/bench.rake +40 -0
  119. data/tasks/gem.rake +8 -0
  120. data/tasks/test.rake +6 -0
  121. metadata +235 -0
@@ -0,0 +1,11 @@
1
+ module Alf
2
+ class Predicate
3
+ module Neq
4
+
5
+ def to_sql_operator
6
+ Sql::Expr::NOT_EQUAL
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module Alf
2
+ class Predicate
3
+ module Not
4
+
5
+ def to_sql(buffer)
6
+ buffer << Sql::Expr::NOT << Sql::Expr::LEFT_PARENTHESE
7
+ last.to_sql(buffer)
8
+ buffer << Sql::Expr::RIGHT_PARENTHESE
9
+ buffer
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Alf
2
+ class Predicate
3
+ module Or
4
+
5
+ def to_sql_operator
6
+ Sql::Expr::OR
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module Alf
2
+ class Predicate
3
+ module QualifiedIdentifier
4
+
5
+ def to_sql(buffer = "")
6
+ buffer << qualifier.to_s << Sql::Expr::DOT << name.to_s
7
+ buffer
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Alf
2
+ class Predicate
3
+ module Tautology
4
+
5
+ def to_sql(buffer)
6
+ buffer << Sql::Expr::TRUE
7
+ buffer
8
+ end
9
+
10
+ end
11
+ end
12
+ end
data/lib/alf/sql.rb ADDED
@@ -0,0 +1,15 @@
1
+ require_relative 'predicate/nodes'
2
+ require_relative 'algebra/operand'
3
+
4
+ require_relative 'sql/version'
5
+ require_relative 'sql/loader'
6
+ module Alf
7
+ module Sql
8
+
9
+ end # module Sql
10
+ end # module Alf
11
+ require_relative 'sql/grammar'
12
+ require_relative 'sql/processor'
13
+ require_relative 'sql/cog'
14
+ require_relative 'sql/builder'
15
+ require_relative 'sql/compiler'
@@ -0,0 +1,152 @@
1
+ module Alf
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
+ SELECT_STAR = Grammar.sexpr([:select_star])
12
+
13
+ def self.builder(meth)
14
+ old = instance_method(meth)
15
+ define_method(meth) do |*args, &bl|
16
+ Grammar.sexpr(old.bind(self).call(*args, &bl))
17
+ end
18
+ end
19
+
20
+ def initialize(start = 0)
21
+ @next_qualifier = (start || 0)
22
+ end
23
+
24
+ def distinct
25
+ DISTINCT
26
+ end
27
+ builder :distinct
28
+
29
+ def all
30
+ ALL
31
+ end
32
+ builder :all
33
+
34
+ def name_intro(name, sexpr)
35
+ [:name_intro, table_name(name), sexpr]
36
+ end
37
+ builder :name_intro
38
+
39
+ def select_all(heading, name, qualifier = next_qualifier!)
40
+ [ :select_exp, all,
41
+ select_list(heading, qualifier),
42
+ from_clause(name, qualifier) ]
43
+ end
44
+ builder :select_all
45
+
46
+ def select_is_table_dee(subquery)
47
+ [ :select_exp, all, is_table_dee,
48
+ [:where_clause, exists(subquery)] ]
49
+ end
50
+ builder :select_is_table_dee
51
+
52
+ def is_table_dee
53
+ IS_TABLE_DEE
54
+ end
55
+ builder :is_table_dee
56
+
57
+ def select_list(heading, qualifier)
58
+ attrs = heading.to_attr_list.to_a
59
+ attrs.map{|a| select_item(qualifier, a) }.unshift(:select_list)
60
+ end
61
+ builder :select_list
62
+
63
+ def select_item(qualifier, name, as = name)
64
+ [:select_item,
65
+ qualified_name(qualifier, name.to_s),
66
+ column_name(as.to_s)]
67
+ end
68
+ builder :select_item
69
+
70
+ def select_star
71
+ SELECT_STAR
72
+ end
73
+ builder :select_star
74
+
75
+ def from_clause(table_name, qualifier)
76
+ [:from_clause,
77
+ table_as(table_name, qualifier) ]
78
+ end
79
+ builder :from_clause
80
+
81
+ def table_as(table, qualifier)
82
+ table = case table
83
+ when String, Symbol then table_name(table)
84
+ else table
85
+ end
86
+ [:table_as,
87
+ table,
88
+ range_var_name(qualifier) ]
89
+ end
90
+ builder :table_as
91
+
92
+ def qualified_name(qualifier, name)
93
+ [:qualified_name,
94
+ range_var_name(qualifier),
95
+ column_name(name) ]
96
+ end
97
+ builder :qualified_name
98
+
99
+ def range_var_name(qualifier)
100
+ [:range_var_name, qualifier]
101
+ end
102
+ builder :range_var_name
103
+
104
+ def column_name(name)
105
+ [:column_name, name]
106
+ end
107
+ builder :column_name
108
+
109
+ def table_name(name)
110
+ [:table_name, name]
111
+ end
112
+ builder :table_name
113
+
114
+ def exists(subquery)
115
+ Predicate::Grammar.sexpr [ :exists, subquery ]
116
+ end
117
+
118
+ def order_by_clause(ordering, &desaliaser)
119
+ ordering.to_a.map{|(s,d)|
120
+ if s.composite?
121
+ raise NotSupportedError, "SQL order by does not support composite selectors"
122
+ end
123
+ name = s.outcoerce.to_s
124
+ name = (desaliaser && desaliaser[name]) || column_name(name)
125
+ [:order_by_term, name, d.to_s]
126
+ }.unshift(:order_by_clause)
127
+ end
128
+ builder :order_by_clause
129
+
130
+ def limit_clause(limit)
131
+ [:limit_clause, limit]
132
+ end
133
+ builder :limit_clause
134
+
135
+ def offset_clause(limit)
136
+ [:offset_clause, limit]
137
+ end
138
+ builder :offset_clause
139
+
140
+ def from_self(sexpr)
141
+ Processor::FromSelf.new(self).call(sexpr)
142
+ end
143
+
144
+ public
145
+
146
+ def next_qualifier!
147
+ "t#{@next_qualifier += 1}"
148
+ end
149
+
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,32 @@
1
+ module Alf
2
+ module Sql
3
+ class Cog
4
+ include Alf::Compiler::Cog
5
+
6
+ def initialize(expr, compiler, sexpr)
7
+ super(expr, compiler)
8
+ @sexpr = sexpr
9
+ end
10
+ attr_reader :sexpr
11
+ alias :to_sexpr :sexpr
12
+
13
+ def cog_orders
14
+ [ sexpr.ordering ].compact
15
+ end
16
+
17
+ def should_be_reused?
18
+ sexpr.should_be_reused?
19
+ end
20
+
21
+ def to_sql(buffer = "")
22
+ sexpr.to_sql(buffer)
23
+ end
24
+
25
+ def each(&bl)
26
+ raise NotSupportedError,\
27
+ "This is an abstract SQL compilation result. Please use alf-sequel."
28
+ end
29
+
30
+ end # module Cog
31
+ end # module Sql
32
+ end # module Alf
@@ -0,0 +1,137 @@
1
+ module Alf
2
+ module Sql
3
+ class Compiler < Alf::Compiler
4
+
5
+ def join(plan)
6
+ Builder.new
7
+ end
8
+
9
+ def supports_reuse?
10
+ true
11
+ end
12
+
13
+ def reuse(plan, cog)
14
+ rewrite(plan, cog.expr, cog, Processor::Requalify, [])
15
+ end
16
+
17
+ def compile(plan, expr, compiled, usage_count)
18
+ cog = super
19
+ if (usage_count > 1) and cog.should_be_reused?
20
+ cog = rewrite(plan, cog.expr, cog, Processor::FromSelf, [])
21
+ end
22
+ cog
23
+ end
24
+
25
+ ### base
26
+
27
+ def on_leaf_operand(plan, expr)
28
+ fresh_cog(expr, builder(plan).select_all(expr.heading, expr.name))
29
+ end
30
+
31
+ ### non-relational
32
+
33
+ def on_clip(plan, expr, compiled)
34
+ rewrite(plan, expr, compiled, Processor::Clip, [expr.attributes, :is_table_dee])
35
+ end
36
+
37
+ def on_sort(plan, expr, compiled)
38
+ if compiled.orderedby?(expr.ordering)
39
+ rebind(plan, expr, compiled)
40
+ else
41
+ rewrite(plan, expr, compiled, Processor::OrderBy, [expr.ordering])
42
+ end
43
+ end
44
+
45
+ ### relational
46
+
47
+ def on_frame(plan, expr, compiled)
48
+ compiled = plan.recompile(compiled){|p|
49
+ p.sort(expr.operand, expr.total_ordering)
50
+ }
51
+ rewrite(plan, expr, compiled, Processor::LimitOffset, [expr.limit, expr.offset])
52
+ end
53
+
54
+ def on_intersect(plan, expr, left, right)
55
+ rewrite(plan, expr, left, Processor::Merge, [:intersect, right.sexpr])
56
+ end
57
+
58
+ def on_join(plan, expr, left, right)
59
+ rewrite(plan, expr, left, Processor::Join, [right.sexpr])
60
+ end
61
+
62
+ def on_matching(plan, expr, left, right)
63
+ rewrite(plan, expr, left, Processor::SemiJoin, [right.sexpr, false])
64
+ end
65
+
66
+ def on_minus(plan, expr, left, right)
67
+ rewrite(plan, expr, left, Processor::Merge, [:except, right.sexpr])
68
+ end
69
+
70
+ def on_not_matching(plan, expr, left, right)
71
+ rewrite(plan, expr, left, Processor::SemiJoin, [right.sexpr, true])
72
+ end
73
+
74
+ def on_page(plan, expr, compiled)
75
+ index, size = expr.page_index, expr.page_size
76
+ compiled = plan.recompile(compiled){|p|
77
+ ordering = expr.total_ordering
78
+ ordering = ordering.reverse if index < 0
79
+ p.sort(expr.operand, ordering)
80
+ }
81
+ rewrite(plan, expr, compiled, Processor::LimitOffset, [size, (index.abs - 1) * size])
82
+ end
83
+
84
+ def on_project(plan, expr, compiled)
85
+ compiled = plan.recompile(compiled){|p|
86
+ p.clip(expr.operand, expr.stay_attributes)
87
+ }
88
+ preserving = expr.key_preserving? rescue false
89
+ if not(preserving) and not(expr.stay_attributes.empty?)
90
+ compiled = rewrite(plan, expr, compiled, Processor::Distinct)
91
+ end
92
+ rebind(plan, expr, compiled)
93
+ end
94
+
95
+ def on_rename(plan, expr, compiled)
96
+ rewrite(plan, expr, compiled, Processor::Rename, [expr.renaming])
97
+ end
98
+
99
+ def on_restrict(plan, expr, compiled)
100
+ rewrite(plan, expr, compiled, Processor::Where, [expr.predicate])
101
+ end
102
+
103
+ # def on_summarize(plan, expr, compiled)
104
+ # # -> SQL's GROUP-BY
105
+ # end
106
+
107
+ def on_union(plan, expr, left, right)
108
+ rewrite(plan, expr, left, Processor::Merge, [:union, right.sexpr])
109
+ end
110
+
111
+ protected
112
+
113
+ def builder(plan)
114
+ plan.options(self)
115
+ end
116
+
117
+ def cog_class
118
+ Cog
119
+ end
120
+
121
+ def fresh_cog(expr, sexpr)
122
+ cog_class.new(expr, self, sexpr)
123
+ end
124
+
125
+ def rewrite(plan, expr, compiled, processor, args = [])
126
+ builder = builder(plan)
127
+ rewrited = processor.new(*args.push(builder)).call(compiled.sexpr)
128
+ cog_class.new(expr, self, rewrited)
129
+ end
130
+
131
+ def rebind(plan, expr, compiled)
132
+ cog_class.new(expr, self, compiled.sexpr)
133
+ end
134
+
135
+ end # class Compilable
136
+ end # module Sql
137
+ end # module Alf
@@ -0,0 +1,44 @@
1
+ module Alf
2
+ module Sql
3
+ Grammar = Sexpr.load(Path.dir/'grammar.sexp.yml')
4
+ module Grammar
5
+
6
+ def tagging_reference
7
+ Sql
8
+ end
9
+
10
+ def default_tagging_module
11
+ Expr
12
+ end
13
+
14
+ end # module Grammar
15
+ end # module Sql
16
+ end # module Alf
17
+ require_relative "nodes/expr"
18
+ require_relative "nodes/set_operator"
19
+ require_relative "nodes/literal"
20
+ require_relative "nodes/column_name"
21
+ require_relative "nodes/qualified_name"
22
+ require_relative "nodes/range_var_name"
23
+ require_relative "nodes/select_exp"
24
+ require_relative "nodes/set_quantifier"
25
+ require_relative "nodes/select_list"
26
+ require_relative "nodes/select_star"
27
+ require_relative "nodes/select_item"
28
+ require_relative "nodes/from_clause"
29
+ require_relative "nodes/table_as"
30
+ require_relative "nodes/subquery_as"
31
+ require_relative "nodes/table_name"
32
+ require_relative "nodes/order_by_clause"
33
+ require_relative "nodes/order_by_term"
34
+ require_relative "nodes/limit_clause"
35
+ require_relative "nodes/offset_clause"
36
+ require_relative "nodes/union"
37
+ require_relative "nodes/intersect"
38
+ require_relative "nodes/except"
39
+ require_relative "nodes/with_exp"
40
+ require_relative "nodes/with_spec"
41
+ require_relative "nodes/name_intro"
42
+ require_relative "nodes/where_clause"
43
+ require_relative "nodes/cross_join"
44
+ require_relative "nodes/inner_join"