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,56 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Merge, "on_with_exp" do
6
+
7
+ subject{ Merge.new(:intersect, right, builder(1)).on_with_exp(expr) }
8
+
9
+ context 'when right is a simple exp' do
10
+ let(:expr){
11
+ # with t1 AS ...
12
+ # SELECT * FROM t1
13
+ with_exp({t1: select_all}, select_all)
14
+ }
15
+
16
+ let(:right){
17
+ # SELECT * FROM t2
18
+ select_all_t2
19
+ }
20
+
21
+ let(:expected){
22
+ # WITH t1 AS ...
23
+ # SELECT * FROM t1 INTERSECT SELECT * FROM t2
24
+ with_exp({t1: select_all}, intersect)
25
+ }
26
+
27
+ it{ should eq(expected) }
28
+ end
29
+
30
+ context 'when right is a with_exp' do
31
+ let(:expr){
32
+ # WITH t1 AS ...
33
+ # SELECT * FROM t1
34
+ with_exp({t1: select_all}, select_all)
35
+ }
36
+
37
+ let(:right){
38
+ # WITH t2 AS ...
39
+ # SELECT * FROM t2
40
+ with_exp({t2: select_all_t2}, select_all_t2)
41
+ }
42
+
43
+ let(:expected){
44
+ # WITH t1 AS ...
45
+ # t2 AS ...
46
+ # SELECT * FROM t1 INTERSECT SELECT * FROM t2
47
+ with_exp({t1: select_all, t2: select_all_t2}, intersect)
48
+ }
49
+
50
+ it{ should eq(expected) }
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe OrderBy, "on_select_exp" do
6
+
7
+ subject{ OrderBy.new(ordering, builder).on_select_exp(expr) }
8
+
9
+ context 'when not already ordered' do
10
+ let(:expr){
11
+ select_all
12
+ }
13
+
14
+ let(:expected){
15
+ select_all.push(order_by_clause)
16
+ }
17
+
18
+ it{ should eq(expected) }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Rename, "on_select_item" do
6
+
7
+ subject{ Rename.new(Renaming[a: :x], Builder.new).on_select_item(expr) }
8
+
9
+ context 'when included' do
10
+ let(:expr){ select_item('a', 'a') }
11
+
12
+ it{ should eq(select_item('a', 'x')) }
13
+ end
14
+
15
+ context 'when already a renaming' do
16
+ let(:expr){ select_item('b', 'a') }
17
+
18
+ it{ should eq(select_item('b', 'x')) }
19
+ end
20
+
21
+ context 'when not matching' do
22
+ let(:expr){ select_item('a', 'y') }
23
+
24
+ it{ should be(expr) }
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Rename, "on_select_list" do
6
+
7
+ subject{ Rename.new(Renaming[a: :b, c: :d], Builder.new).on_select_list(expr) }
8
+
9
+ let(:expr){
10
+ select_list("a" => "a", "x" => "c", "y" => "z")
11
+ }
12
+
13
+ let(:expected){
14
+ select_list("a" => "b", "x" => "d", "y" => "z")
15
+ }
16
+
17
+ it{ should eq(expected) }
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Reorder, "on_select_list" do
6
+
7
+ subject{ Reorder.new([:b, :a], Builder.new).on_select_list(expr) }
8
+
9
+ let(:expr){
10
+ select_list_ab
11
+ }
12
+
13
+ let(:expected){
14
+ select_list_ba
15
+ }
16
+
17
+ it{ should eq(expected) }
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Requalify, "on_select_exp" do
6
+
7
+ subject{ Requalify.new(Builder.new(1)).on_select_exp(expr) }
8
+
9
+ context 'when not already ordered' do
10
+ let(:expr){
11
+ select_all
12
+ }
13
+
14
+ let(:expected){
15
+ select_all_from_t1_as_t2
16
+ }
17
+
18
+ it{ should eq(expected) }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Star, "on_select_list" do
6
+
7
+ subject{ Star.new(Builder.new).on_select_exp(expr) }
8
+
9
+ context 'on select_all' do
10
+ let(:expr){ select_all }
11
+
12
+ it{ should eq(select_all_star) }
13
+ end
14
+
15
+ context 'on select_distinct' do
16
+ let(:expr){ select_distinct }
17
+
18
+ it{ should eq(select_distinct_star) }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Clip do
6
+
7
+ subject{ Clip.new([:a], Builder.new).call(expr) }
8
+
9
+ context 'on a select_exp' do
10
+ let(:expr){ select_ab }
11
+
12
+ it{ should eq(select_a) }
13
+ end
14
+
15
+ context 'on a with_exp' do
16
+ let(:expr){ with_exp(nil, select_ab) }
17
+
18
+ it{ should eq(with_exp(nil, select_a)) }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Distinct do
6
+
7
+ subject{ Distinct.new(Builder.new).call(expr) }
8
+
9
+ context 'on a select_exp' do
10
+ let(:expr){ select_all }
11
+
12
+ it{ should eq(select_distinct) }
13
+ end
14
+
15
+ context 'on a with_exp' do
16
+ let(:expr){ with_exp(nil, select_all) }
17
+
18
+ it{ should eq(with_exp(nil, select_distinct)) }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ describe Processor, "on_select_exp" do
5
+
6
+ let(:clazz){
7
+ Class.new(Processor){
8
+ def on_select_list(sexpr)
9
+ [:foo, :bar, sexpr]
10
+ end
11
+ }
12
+ }
13
+
14
+ subject{ clazz.new(Builder.new).on_select_exp(expr) }
15
+
16
+ let(:expr){
17
+ Grammar.sexpr [:select_exp, distinct, select_list_ab, [:baz]]
18
+ }
19
+
20
+ let(:expected){
21
+ [:select_exp, distinct, [:foo, :bar, select_list_ab], [:baz]]
22
+ }
23
+
24
+ it{ should eq(expected) }
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ describe Processor, "on_set_operator" do
5
+
6
+ let(:clazz){
7
+ Class.new(Processor){
8
+ def on_select_exp(sexpr)
9
+ [:foo, :bar, sexpr]
10
+ end
11
+ }
12
+ }
13
+
14
+ subject{ clazz.new(Builder.new).on_set_operator(expr) }
15
+
16
+ let(:expr){
17
+ [:union, all, select_all_a, select_all_b]
18
+ }
19
+
20
+ let(:expected){
21
+ [:union, all, [:foo, :bar, select_all_a], [:foo, :bar, select_all_b]]
22
+ }
23
+
24
+ it{ should eq(expected) }
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Sql
4
+ class Processor
5
+ describe Rename do
6
+
7
+ subject{ Rename.new(Renaming[a: :b], Builder.new).call(expr) }
8
+
9
+ context 'on a select_exp' do
10
+ let(:expr){ select_all_a }
11
+
12
+ it{ should eq(select_all_a_as_b) }
13
+ end
14
+
15
+ context 'on a with_exp' do
16
+ let(:expr){ with_exp(nil, select_all_a) }
17
+
18
+ it{ should eq(with_exp(nil, select_all_a_as_b)) }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ shared_examples_for "a compiled" do
2
+
3
+ it{ should be_a(Alf::Sql::Cog) }
4
+
5
+ it 'has correct traceability' do
6
+ subject.expr.should be(expr)
7
+ end
8
+
9
+ it 'has correct compiler' do
10
+ subject.compiler.should be(compiler)
11
+ end
12
+
13
+ end
@@ -0,0 +1,14 @@
1
+ require 'alf-core'
2
+ require 'alf-sql'
3
+ require "rspec"
4
+
5
+ require_relative 'helpers/ast'
6
+ require_relative 'helpers/compiler'
7
+
8
+ require_relative 'shared/compiled_examples'
9
+
10
+ RSpec.configure do |c|
11
+ c.include Alf::Lang::Functional
12
+ c.include Helpers
13
+ c.extend Helpers
14
+ end
data/spec/test_sql.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ describe Sql do
4
+
5
+ it "should have a version number" do
6
+ Sql.const_defined?(:VERSION).should be_true
7
+ end
8
+
9
+ end
10
+ end
data/tasks/bench.rake ADDED
@@ -0,0 +1,40 @@
1
+ namespace :bench do
2
+
3
+ def bench_cmd
4
+ "bundle exec ruby -Ilib -I spec/integration/ spec/integration/bench_all.rb"
5
+ end
6
+
7
+ def alf_cmd(tail)
8
+ "bundle exec alf --ff=%.6f --input-reader=rash #{tail}"
9
+ end
10
+
11
+ task :run do
12
+ cmd = bench_cmd
13
+ $stderr.puts cmd
14
+ exec(cmd)
15
+ end
16
+
17
+ task :summary do
18
+ cmd = bench_cmd
19
+ cmd << " | "
20
+ cmd << alf_cmd("summarize -- category -- min 'min{ total }' max 'max{ total }' avg 'avg{ total }' stddev 'stddev{ total }'")
21
+ $stderr.puts cmd
22
+ exec(cmd)
23
+ end
24
+
25
+ task :rank do
26
+ cmd = bench_cmd
27
+ cmd << " | "
28
+ cmd << alf_cmd("summarize -- category alf -- parsing 'avg{ parsing }' compiling 'avg{ compiling }' translating 'avg{ translating }' printing 'avg{ printing }' total 'avg{ total }'")
29
+ cmd << " | "
30
+ cmd << alf_cmd("rank -- total desc -- position")
31
+ cmd << " | "
32
+ cmd << alf_cmd("project -- position category alf parsing compiling printing total")
33
+ cmd << " | "
34
+ cmd << alf_cmd("restrict -- 'position < 10'")
35
+ $stderr.puts cmd
36
+ exec(cmd)
37
+ end
38
+
39
+ end
40
+ task :bench => :"bench:run"
data/tasks/gem.rake ADDED
@@ -0,0 +1,8 @@
1
+ require 'rubygems/package_task'
2
+ gemspec_file = File.expand_path('../../alf-sql.gemspec', __FILE__)
3
+ gemspec = Kernel.eval(File.read(gemspec_file))
4
+ Gem::PackageTask.new(gemspec) do |t|
5
+ t.name = gemspec.name
6
+ t.version = gemspec.version
7
+ t.package_files = gemspec.files
8
+ end