alf-sql 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +38 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +12 -0
- data/README.md +52 -0
- data/Rakefile +11 -0
- data/lib/alf-sql.rb +1 -0
- data/lib/alf/algebra/operand.rb +18 -0
- data/lib/alf/predicate/nodes.rb +20 -0
- data/lib/alf/predicate/nodes/and.rb +11 -0
- data/lib/alf/predicate/nodes/contradiction.rb +12 -0
- data/lib/alf/predicate/nodes/dyadic_comp.rb +14 -0
- data/lib/alf/predicate/nodes/eq.rb +11 -0
- data/lib/alf/predicate/nodes/exists.rb +14 -0
- data/lib/alf/predicate/nodes/expr.rb +20 -0
- data/lib/alf/predicate/nodes/gt.rb +11 -0
- data/lib/alf/predicate/nodes/gte.rb +11 -0
- data/lib/alf/predicate/nodes/identifier.rb +12 -0
- data/lib/alf/predicate/nodes/in.rb +31 -0
- data/lib/alf/predicate/nodes/literal.rb +12 -0
- data/lib/alf/predicate/nodes/lt.rb +11 -0
- data/lib/alf/predicate/nodes/lte.rb +11 -0
- data/lib/alf/predicate/nodes/nadic_bool.rb +18 -0
- data/lib/alf/predicate/nodes/native.rb +11 -0
- data/lib/alf/predicate/nodes/neq.rb +11 -0
- data/lib/alf/predicate/nodes/not.rb +14 -0
- data/lib/alf/predicate/nodes/or.rb +11 -0
- data/lib/alf/predicate/nodes/qualified_identifier.rb +12 -0
- data/lib/alf/predicate/nodes/tautology.rb +12 -0
- data/lib/alf/sql.rb +15 -0
- data/lib/alf/sql/builder.rb +152 -0
- data/lib/alf/sql/cog.rb +32 -0
- data/lib/alf/sql/compiler.rb +137 -0
- data/lib/alf/sql/grammar.rb +44 -0
- data/lib/alf/sql/grammar.sexp.yml +92 -0
- data/lib/alf/sql/loader.rb +2 -0
- data/lib/alf/sql/nodes/column_name.rb +25 -0
- data/lib/alf/sql/nodes/cross_join.rb +28 -0
- data/lib/alf/sql/nodes/except.rb +14 -0
- data/lib/alf/sql/nodes/expr.rb +90 -0
- data/lib/alf/sql/nodes/from_clause.rb +24 -0
- data/lib/alf/sql/nodes/inner_join.rb +37 -0
- data/lib/alf/sql/nodes/intersect.rb +14 -0
- data/lib/alf/sql/nodes/limit_clause.rb +19 -0
- data/lib/alf/sql/nodes/literal.rb +18 -0
- data/lib/alf/sql/nodes/name_intro.rb +23 -0
- data/lib/alf/sql/nodes/offset_clause.rb +19 -0
- data/lib/alf/sql/nodes/order_by_clause.rb +25 -0
- data/lib/alf/sql/nodes/order_by_term.rb +30 -0
- data/lib/alf/sql/nodes/qualified_name.rb +32 -0
- data/lib/alf/sql/nodes/range_var_name.rb +17 -0
- data/lib/alf/sql/nodes/select_exp.rb +101 -0
- data/lib/alf/sql/nodes/select_item.rb +37 -0
- data/lib/alf/sql/nodes/select_list.rb +31 -0
- data/lib/alf/sql/nodes/select_star.rb +15 -0
- data/lib/alf/sql/nodes/set_operator.rb +64 -0
- data/lib/alf/sql/nodes/set_quantifier.rb +20 -0
- data/lib/alf/sql/nodes/subquery_as.rb +28 -0
- data/lib/alf/sql/nodes/table_as.rb +31 -0
- data/lib/alf/sql/nodes/table_name.rb +17 -0
- data/lib/alf/sql/nodes/union.rb +14 -0
- data/lib/alf/sql/nodes/where_clause.rb +20 -0
- data/lib/alf/sql/nodes/with_exp.rb +50 -0
- data/lib/alf/sql/nodes/with_spec.rb +24 -0
- data/lib/alf/sql/processor.rb +85 -0
- data/lib/alf/sql/processor/all.rb +17 -0
- data/lib/alf/sql/processor/clip.rb +39 -0
- data/lib/alf/sql/processor/distinct.rb +17 -0
- data/lib/alf/sql/processor/flatten.rb +24 -0
- data/lib/alf/sql/processor/from_self.rb +29 -0
- data/lib/alf/sql/processor/join.rb +80 -0
- data/lib/alf/sql/processor/join_support.rb +27 -0
- data/lib/alf/sql/processor/limit_offset.rb +30 -0
- data/lib/alf/sql/processor/merge.rb +42 -0
- data/lib/alf/sql/processor/order_by.rb +32 -0
- data/lib/alf/sql/processor/rename.rb +25 -0
- data/lib/alf/sql/processor/reorder.rb +21 -0
- data/lib/alf/sql/processor/requalify.rb +24 -0
- data/lib/alf/sql/processor/semi_join.rb +57 -0
- data/lib/alf/sql/processor/star.rb +17 -0
- data/lib/alf/sql/processor/where.rb +25 -0
- data/lib/alf/sql/version.rb +16 -0
- data/spec/algebra/operand/test_to_sql.rb +32 -0
- data/spec/builder/test_order_by_clause.rb +44 -0
- data/spec/helpers/ast.rb +242 -0
- data/spec/helpers/compiler.rb +23 -0
- data/spec/nodes/column_name/test_as_name.rb +14 -0
- data/spec/nodes/column_name/test_qualifier.rb +14 -0
- data/spec/nodes/order_by_clause/test_to_ordering.rb +30 -0
- data/spec/nodes/order_by_term/test_as_name.rb +22 -0
- data/spec/nodes/order_by_term/test_direction.rb +22 -0
- data/spec/nodes/order_by_term/test_qualifier.rb +22 -0
- data/spec/nodes/select_exp/test_order_by_clause.rb +22 -0
- data/spec/nodes/select_item/test_as_name.rb +22 -0
- data/spec/predicate/nodes/exists/test_not.rb +20 -0
- data/spec/processor/clip/test_on_select_exp.rb +32 -0
- data/spec/processor/clip/test_on_select_list.rb +24 -0
- data/spec/processor/distinct/test_on_set_quantified.rb +31 -0
- data/spec/processor/from_self/test_on_nonjoin_exp.rb +60 -0
- data/spec/processor/from_self/test_on_with_exp.rb +22 -0
- data/spec/processor/merge/test_on_select_exp.rb +73 -0
- data/spec/processor/merge/test_on_with_exp.rb +56 -0
- data/spec/processor/order_by/test_on_select_exp.rb +24 -0
- data/spec/processor/rename/test_on_select_item.rb +30 -0
- data/spec/processor/rename/test_on_select_list.rb +22 -0
- data/spec/processor/reorder/test_on_select_list.rb +22 -0
- data/spec/processor/requalify/test_on_select_exp.rb +24 -0
- data/spec/processor/star/test_on_select_exp.rb +24 -0
- data/spec/processor/test_clip.rb +24 -0
- data/spec/processor/test_distinct.rb +24 -0
- data/spec/processor/test_on_select_exp.rb +28 -0
- data/spec/processor/test_on_set_operator.rb +28 -0
- data/spec/processor/test_rename.rb +24 -0
- data/spec/shared/compiled_examples.rb +13 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/test_sql.rb +10 -0
- data/tasks/bench.rake +40 -0
- data/tasks/gem.rake +8 -0
- data/tasks/test.rake +6 -0
- 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
|
data/spec/spec_helper.rb
ADDED
@@ -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
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
|