alf-sequel 0.13.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.
- data/CHANGELOG.md +4 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +38 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +12 -0
- data/README.md +11 -0
- data/Rakefile +11 -0
- data/lib/alf/sequel/adapter.rb +57 -0
- data/lib/alf/sequel/cog.rb +92 -0
- data/lib/alf/sequel/compiler/predicate.rb +76 -0
- data/lib/alf/sequel/compiler.rb +168 -0
- data/lib/alf/sequel/connection/connection_methods.rb +46 -0
- data/lib/alf/sequel/connection/schema_methods.rb +76 -0
- data/lib/alf/sequel/connection/update_methods.rb +63 -0
- data/lib/alf/sequel/connection.rb +23 -0
- data/lib/alf/sequel/loader.rb +2 -0
- data/lib/alf/sequel/unit_of_work/atomic.rb +35 -0
- data/lib/alf/sequel/unit_of_work/delete.rb +24 -0
- data/lib/alf/sequel/unit_of_work/insert.rb +60 -0
- data/lib/alf/sequel/unit_of_work/update.rb +60 -0
- data/lib/alf/sequel/unit_of_work.rb +11 -0
- data/lib/alf/sequel/version.rb +16 -0
- data/lib/alf/sequel.rb +7 -0
- data/lib/alf-sequel.rb +1 -0
- data/spec/adapter/test_recognize.rb +50 -0
- data/spec/alf.db +0 -0
- data/spec/compiler/test_clip.rb +40 -0
- data/spec/compiler/test_compact.rb +18 -0
- data/spec/compiler/test_extend.rb +16 -0
- data/spec/compiler/test_intersect.rb +18 -0
- data/spec/compiler/test_join.rb +18 -0
- data/spec/compiler/test_leaf_operand.rb +24 -0
- data/spec/compiler/test_matching.rb +34 -0
- data/spec/compiler/test_not_matching.rb +34 -0
- data/spec/compiler/test_predicate.rb +141 -0
- data/spec/compiler/test_project.rb +64 -0
- data/spec/compiler/test_rename.rb +26 -0
- data/spec/compiler/test_restrict.rb +48 -0
- data/spec/compiler/test_sort.rb +18 -0
- data/spec/compiler/test_union.rb +18 -0
- data/spec/compiler_helper.rb +34 -0
- data/spec/connection/test_connection_uri.rb +54 -0
- data/spec/connection/test_delete.rb +20 -0
- data/spec/connection/test_heading.rb +16 -0
- data/spec/connection/test_insert.rb +24 -0
- data/spec/connection/test_keys.rb +24 -0
- data/spec/connection/test_lock.rb +15 -0
- data/spec/connection/test_ping.rb +26 -0
- data/spec/connection/test_relvar.rb +16 -0
- data/spec/connection/test_update.rb +20 -0
- data/spec/fixtures/sap.db +0 -0
- data/spec/fixtures/sap.rb +43 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/test_assumptions.rb +14 -0
- data/spec/test_sequel.rb +10 -0
- data/spec/unit_of_work/atomic/test_run.rb +72 -0
- data/spec/unit_of_work/delete/test_delete.rb +39 -0
- data/spec/unit_of_work/insert/test_run.rb +71 -0
- data/spec/unit_of_work/update/test_run.rb +39 -0
- data/tasks/fixtures.rake +12 -0
- data/tasks/gem.rake +8 -0
- data/tasks/test.rake +6 -0
- metadata +174 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
#
|
4
|
+
# Specialization of Alf::Connection to distribute Sequel datasets
|
5
|
+
#
|
6
|
+
class Connection < Alf::Adapter::Connection
|
7
|
+
|
8
|
+
def compiler
|
9
|
+
Compiler.new
|
10
|
+
end
|
11
|
+
|
12
|
+
require_relative 'connection/schema_methods'
|
13
|
+
require_relative 'connection/connection_methods'
|
14
|
+
require_relative 'connection/update_methods'
|
15
|
+
include SchemaMethods
|
16
|
+
include ConnectionMethods
|
17
|
+
include UpdateMethods
|
18
|
+
|
19
|
+
alias_method :to_s, :connection_uri
|
20
|
+
|
21
|
+
end # class Connection
|
22
|
+
end # module Sequel
|
23
|
+
end # module Alf
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
module UnitOfWork
|
4
|
+
module Atomic
|
5
|
+
|
6
|
+
def initialize(connection)
|
7
|
+
@connection = connection
|
8
|
+
@ran = false
|
9
|
+
@failure = nil
|
10
|
+
end
|
11
|
+
attr_reader :connection, :failure
|
12
|
+
|
13
|
+
def ran?
|
14
|
+
@ran
|
15
|
+
end
|
16
|
+
|
17
|
+
def failed?
|
18
|
+
not(@failure.nil?)
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
raise IllegalStateError, "Unit of work already ran" if ran?
|
23
|
+
_run
|
24
|
+
self
|
25
|
+
rescue => ex
|
26
|
+
@failure = ex
|
27
|
+
raise
|
28
|
+
ensure
|
29
|
+
@ran = true
|
30
|
+
end
|
31
|
+
|
32
|
+
end # module Atomic
|
33
|
+
end # module UnitOfWork
|
34
|
+
end # module Sequel
|
35
|
+
end # module Alf
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
module UnitOfWork
|
4
|
+
class Delete
|
5
|
+
include UnitOfWork::Atomic
|
6
|
+
|
7
|
+
def initialize(connection, relvar_name, predicate)
|
8
|
+
super(connection)
|
9
|
+
@relvar_name = relvar_name
|
10
|
+
@predicate = predicate
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def _run
|
16
|
+
connection.with_dataset(@relvar_name, @predicate) do |d|
|
17
|
+
d.delete
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end # class Delete
|
22
|
+
end # module UnitOfWork
|
23
|
+
end # module Sequel
|
24
|
+
end # module Alf
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
module UnitOfWork
|
4
|
+
class Insert
|
5
|
+
include UnitOfWork::Atomic
|
6
|
+
|
7
|
+
def initialize(connection, relvar_name, inserted)
|
8
|
+
super(connection)
|
9
|
+
@relvar_name = relvar_name
|
10
|
+
@inserted = inserted
|
11
|
+
@insert_result = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def matching_relation
|
15
|
+
@matching_relation ||= begin
|
16
|
+
raise IllegalStateError, "Unit of work not ran" unless ran?
|
17
|
+
unless @insert_result
|
18
|
+
raise UnsupportedError, "Composite keys insertion feedback is unsupported."
|
19
|
+
end
|
20
|
+
Relation(@insert_result)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def candidate_keys
|
27
|
+
@candidate_keys ||= connection.keys(@relvar_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def primary_key
|
31
|
+
candidate_keys.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def best_candidate_key
|
35
|
+
best = candidate_keys.to_a.find{|k| k.size == 1}
|
36
|
+
best || candidate_keys.first
|
37
|
+
end
|
38
|
+
|
39
|
+
def _run
|
40
|
+
connection.with_dataset(@relvar_name) do |d|
|
41
|
+
bk = best_candidate_key
|
42
|
+
if bk and bk.size == 1
|
43
|
+
pk_field_name = bk.to_a.first
|
44
|
+
supported = d.supports_returning?(:insert)
|
45
|
+
d = d.returning(pk_field_name) if supported
|
46
|
+
@insert_result = @inserted.map{|t|
|
47
|
+
res = d.insert(t.to_hash)
|
48
|
+
supported ? res.first : { pk_field_name => res }
|
49
|
+
}
|
50
|
+
else
|
51
|
+
@inserted.each{|t| d.insert(t.to_hash) }
|
52
|
+
@insert_result = nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end # class Insert
|
58
|
+
end # module UnitOfWork
|
59
|
+
end # module Sequel
|
60
|
+
end # module Alf
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
module UnitOfWork
|
4
|
+
class Update
|
5
|
+
include UnitOfWork::Atomic
|
6
|
+
|
7
|
+
def initialize(connection, relvar_name, updating, predicate)
|
8
|
+
super(connection)
|
9
|
+
@relvar_name = relvar_name
|
10
|
+
@updating = updating
|
11
|
+
@predicate = predicate
|
12
|
+
end
|
13
|
+
|
14
|
+
def matching_relation
|
15
|
+
raise IllegalStateError, "Unit of work not ran" unless ran?
|
16
|
+
|
17
|
+
# Check that updating is understandable
|
18
|
+
unless TupleLike===@updating
|
19
|
+
raise UnsupportedError, "Non-tuple update feedback is unsupported."
|
20
|
+
end
|
21
|
+
updating = @updating.to_hash
|
22
|
+
updating_keys = updating.keys
|
23
|
+
|
24
|
+
# extract all keys, and pk in particular
|
25
|
+
keys = connection.keys(@relvar_name)
|
26
|
+
pk = keys.first
|
27
|
+
|
28
|
+
# Strategy 1), @updating contains a key
|
29
|
+
if key = keys.to_a.find{|k| !(k & updating_keys).empty? }
|
30
|
+
return Relation(@updating.project(key).to_hash)
|
31
|
+
end
|
32
|
+
|
33
|
+
raise UnsupportedError, "Unable to extract update matching relation"
|
34
|
+
end
|
35
|
+
|
36
|
+
def pk_matching_relation
|
37
|
+
mr, pkey = matching_relation, connection.keys(@relvar_name).first
|
38
|
+
if mr.to_attr_list == pkey.to_attr_list
|
39
|
+
mr
|
40
|
+
else
|
41
|
+
filter = mr.tuple_extract.to_hash
|
42
|
+
tuples = connection.cog(@relvar_name)
|
43
|
+
.filter(filter)
|
44
|
+
.select(pkey.to_a)
|
45
|
+
Relation(tuples)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def _run
|
52
|
+
connection.with_dataset(@relvar_name, @predicate) do |d|
|
53
|
+
d.update Tuple(@updating).to_hash
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end # class Update
|
58
|
+
end # module UnitOfWork
|
59
|
+
end # module Sequel
|
60
|
+
end # module Alf
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
module UnitOfWork
|
4
|
+
|
5
|
+
end # module UnitOfWork
|
6
|
+
end # module Sequel
|
7
|
+
end # module Alf
|
8
|
+
require_relative 'unit_of_work/atomic'
|
9
|
+
require_relative 'unit_of_work/insert'
|
10
|
+
require_relative 'unit_of_work/delete'
|
11
|
+
require_relative 'unit_of_work/update'
|
data/lib/alf/sequel.rb
ADDED
data/lib/alf-sequel.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "alf/sequel"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Adapter, "recognizes?" do
|
5
|
+
|
6
|
+
it "recognizes ::Sequel::Database objects" do
|
7
|
+
begin
|
8
|
+
db = ::Sequel.connect(sequel_database_memory)
|
9
|
+
Adapter.recognizes?(db).should be_true
|
10
|
+
ensure
|
11
|
+
db.disconnect if db
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "recognizes sqlite files" do
|
16
|
+
Adapter.recognizes?("#{sequel_database_path}").should be_true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "recognizes in memory sqlite databases" do
|
20
|
+
Adapter.recognizes?(sequel_database_memory).should be_true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "recognizes a Path to a sqlite databases" do
|
24
|
+
Adapter.recognizes?(sequel_database_path).should be_true
|
25
|
+
Adapter.recognizes?("nosuchone.db").should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "recognizes database uris" do
|
29
|
+
Adapter.recognizes?("postgres://localhost/database").should be_true
|
30
|
+
Adapter.recognizes?(sequel_database_uri).should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "recognizes a Hash ala Rails" do
|
34
|
+
config = {"adapter" => "sqlite", "database" => "#{sequel_database_path}"}
|
35
|
+
Adapter.recognizes?(config).should be_true
|
36
|
+
Adapter.recognizes?(Tools.symbolize_keys(config)).should be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not be too permissive" do
|
40
|
+
Adapter.recognizes?(nil).should be_false
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should let Adapter autodetect sqlite files" do
|
44
|
+
Alf::Adapter.autodetect(sequel_database_path).should be(Adapter)
|
45
|
+
Alf::Adapter.autodetect("#{sequel_database_path}").should be(Adapter)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/alf.db
ADDED
Binary file
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "clip" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'when the operand is fully compilable' do
|
9
|
+
let(:expr){ clip(suppliers, [:sid, :name]) }
|
10
|
+
|
11
|
+
specify{
|
12
|
+
subject.sql.should eq("SELECT `t1`.`sid`, `t1`.`name` FROM `suppliers` AS 't1'")
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when the operand is fully compilable (distinct normally needed)' do
|
17
|
+
let(:expr){ clip(suppliers, [:city]) }
|
18
|
+
|
19
|
+
specify{
|
20
|
+
subject.sql.should eq("SELECT `t1`.`city` FROM `suppliers` AS 't1'")
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when the operand is fully compilable (allbut, distinct)' do
|
25
|
+
let(:expr){ clip(suppliers, [:sid, :name, :status], :allbut => true) }
|
26
|
+
|
27
|
+
specify{
|
28
|
+
subject.sql.should eq("SELECT `t1`.`city` FROM `suppliers` AS 't1'")
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when the operand is not compilable' do
|
33
|
+
let(:expr){ clip(an_operand, [:sid, :name]) }
|
34
|
+
|
35
|
+
it{ should be_a(Engine::Cog) }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "compact" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'when the operand is fully compilable' do
|
9
|
+
let(:expr){ compact(suppliers) }
|
10
|
+
|
11
|
+
specify{
|
12
|
+
subject.sql.should eq("SELECT DISTINCT * FROM `suppliers` AS 't1'")
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "extend" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'with a native predicate' do
|
9
|
+
let(:expr){ extend(suppliers, :big => lambda{}) }
|
10
|
+
|
11
|
+
it{ should be_a(Engine::SetAttr) }
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "intersect" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'when the operand is fully compilable' do
|
9
|
+
let(:expr){ intersect(suppliers, supplies) }
|
10
|
+
|
11
|
+
specify do
|
12
|
+
subject.sql.should eq("SELECT * FROM (SELECT * FROM `suppliers` AS 't1' INTERSECT SELECT * FROM `supplies` AS 't2') AS 't3'")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "join" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'when the operand is fully compilable' do
|
9
|
+
let(:expr){ join(suppliers, supplies) }
|
10
|
+
|
11
|
+
specify do
|
12
|
+
subject.sql.should eq("SELECT * FROM (SELECT * FROM `suppliers` AS 't1' INNER JOIN (SELECT * FROM `supplies` AS 't2') AS 't3' USING (`sid`)) AS 't3'")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "leaf_operand" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'on the proper context' do
|
9
|
+
let(:expr){ suppliers }
|
10
|
+
|
11
|
+
it{ should be_a(Cog) }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'on another context' do
|
15
|
+
let(:expr){ Algebra.named_operand(:suppliers, self) }
|
16
|
+
|
17
|
+
pending "support for multiple context is needed" do
|
18
|
+
it{ should_not be_a(Cog) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "matching" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'when no common attributes' do
|
9
|
+
let(:expr){ matching(suppliers, project(supplies, [:part_id])) }
|
10
|
+
|
11
|
+
specify do
|
12
|
+
subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (EXISTS (SELECT `t2`.`part_id` FROM `supplies` AS 't2'))")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when only one common attributes' do
|
17
|
+
let(:expr){ matching(suppliers, supplies) }
|
18
|
+
|
19
|
+
specify do
|
20
|
+
subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (`t1`.`sid` IN (SELECT `t2`.`sid` FROM `supplies` AS 't2'))")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when many common attributes' do
|
25
|
+
let(:expr){ matching(suppliers, parts) }
|
26
|
+
|
27
|
+
specify do
|
28
|
+
subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (EXISTS (SELECT * FROM `parts` AS 't2' WHERE ((`t1`.`name` = `t2`.`name`) AND (`t1`.`city` = `t2`.`city`))))")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
describe Compiler, "not_matching" do
|
5
|
+
|
6
|
+
subject{ compile(expr) }
|
7
|
+
|
8
|
+
context 'when no common attributes' do
|
9
|
+
let(:expr){ not_matching(suppliers, project(supplies, [:part_id])) }
|
10
|
+
|
11
|
+
specify do
|
12
|
+
subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE NOT (EXISTS (SELECT `t2`.`part_id` FROM `supplies` AS 't2'))")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when only one common attributes' do
|
17
|
+
let(:expr){ not_matching(suppliers, supplies) }
|
18
|
+
|
19
|
+
specify do
|
20
|
+
subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (`t1`.`sid` NOT IN (SELECT `t2`.`sid` FROM `supplies` AS 't2'))")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when many common attributes' do
|
25
|
+
let(:expr){ not_matching(suppliers, parts) }
|
26
|
+
|
27
|
+
specify do
|
28
|
+
subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE NOT (EXISTS (SELECT * FROM `parts` AS 't2' WHERE ((`t1`.`name` = `t2`.`name`) AND (`t1`.`city` = `t2`.`city`))))")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'compiler_helper'
|
2
|
+
module Alf
|
3
|
+
module Sequel
|
4
|
+
class Compiler
|
5
|
+
describe Predicate do
|
6
|
+
|
7
|
+
let(:p) { Alf::Predicate }
|
8
|
+
let(:compiler) { Predicate.new }
|
9
|
+
let(:dataset) { sap.cog(:suppliers).dataset }
|
10
|
+
let(:compiled) { compiler.call(expr) }
|
11
|
+
|
12
|
+
subject{ dataset.literal(compiled) }
|
13
|
+
|
14
|
+
context 'tautology' do
|
15
|
+
let(:expr){ p.tautology }
|
16
|
+
|
17
|
+
it{ should eq("(1 = 1)") }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'contradiction' do
|
21
|
+
let(:expr){ p.contradiction }
|
22
|
+
|
23
|
+
it{ should eq("(1 = 0)") }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'var_ref' do
|
27
|
+
let(:expr){ p.var_ref(:x) }
|
28
|
+
|
29
|
+
it{ should eq("`x`") }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'literal' do
|
33
|
+
let(:expr){ p.literal(12) }
|
34
|
+
|
35
|
+
it{ should eq("12") }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'eq(var, literal)' do
|
39
|
+
let(:expr){ p.eq(:x, 12) }
|
40
|
+
|
41
|
+
it{ should eq("(`x` = 12)") }
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'neq(var, literal)' do
|
45
|
+
let(:expr){ p.neq(:x, 12) }
|
46
|
+
|
47
|
+
it{ should eq("(`x` != 12)") }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'eq(var, nil)' do
|
51
|
+
let(:expr){ p.eq(:x, nil) }
|
52
|
+
|
53
|
+
it{ should eq("(`x` IS NULL)") }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'eq(var, var)' do
|
57
|
+
let(:expr){ p.eq(:x, :y) }
|
58
|
+
|
59
|
+
it{ should eq("(`x` = `y`)") }
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'lt(var, literal)' do
|
63
|
+
let(:expr){ p.lt(:x, 2) }
|
64
|
+
|
65
|
+
it{ should eq("(`x` < 2)") }
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'lte(var, literal)' do
|
69
|
+
let(:expr){ p.lte(:x, 2) }
|
70
|
+
|
71
|
+
it{ should eq("(`x` <= 2)") }
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'gt(var, literal)' do
|
75
|
+
let(:expr){ p.gt(:x, 2) }
|
76
|
+
|
77
|
+
it{ should eq("(`x` > 2)") }
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'gte(var, literal)' do
|
81
|
+
let(:expr){ p.gte(:x, 2) }
|
82
|
+
|
83
|
+
it{ should eq("(`x` >= 2)") }
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'not(var)' do
|
87
|
+
let(:expr){ p.not(:x) }
|
88
|
+
|
89
|
+
it{ should eq("NOT `x`") }
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'not(tautology)' do
|
93
|
+
let(:expr){ p.not(true) }
|
94
|
+
|
95
|
+
it{ should eq("(1 = 0)") }
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'and' do
|
99
|
+
let(:expr){ p.eq(:x, 2) & p.eq(:y, 3) }
|
100
|
+
|
101
|
+
it{ should eq("((`x` = 2) AND (`y` = 3))") }
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'or' do
|
105
|
+
let(:expr){ p.eq(:x, 2) | p.eq(:y, 3) }
|
106
|
+
|
107
|
+
it{ should eq("((`x` = 2) OR (`y` = 3))") }
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'comp' do
|
111
|
+
let(:expr){ p.comp(:lt, :x => 2, :y => 3) }
|
112
|
+
|
113
|
+
it{ should eq("((`x` < 2) AND (`y` < 3))") }
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'in' do
|
117
|
+
let(:expr){ p.in(:x, [2, 3]) }
|
118
|
+
|
119
|
+
it{ should eq("(`x` IN (2, 3))") }
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'in with a dataset at right' do
|
123
|
+
let(:expr){ p.in(:x, dataset) }
|
124
|
+
|
125
|
+
it{ should eq("(`x` IN (SELECT * FROM `suppliers`))") }
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'native' do
|
129
|
+
let(:expr){ p.native(lambda{}) }
|
130
|
+
|
131
|
+
specify{
|
132
|
+
lambda{
|
133
|
+
subject
|
134
|
+
}.should throw_symbol(:pass)
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|