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
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
group :runtime do
|
4
|
+
#gem "alf-core", :git => "git://github.com/alf-tool/alf-core.git"
|
5
|
+
gem "alf-core", "~> 0.13.0"
|
6
|
+
gem "sequel", "~> 3.48"
|
7
|
+
end
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem "rake", "~> 10.1"
|
11
|
+
gem "rspec", "~> 2.14"
|
12
|
+
gem "sqlite3", "~> 1.3", :platforms => ['mri', 'rbx']
|
13
|
+
gem "jdbc-sqlite3", "~> 3.7", :platforms => ['jruby']
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development do
|
17
|
+
gem "rake", "~> 10.1"
|
18
|
+
gem "rspec", "~> 2.14"
|
19
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
alf-core (0.13.0)
|
5
|
+
domain (~> 1.0)
|
6
|
+
myrrha (~> 3.0)
|
7
|
+
path (~> 1.3)
|
8
|
+
sexpr (~> 0.5.1)
|
9
|
+
diff-lcs (1.2.4)
|
10
|
+
domain (1.0.0)
|
11
|
+
jdbc-sqlite3 (3.7.2.1)
|
12
|
+
myrrha (3.0.0)
|
13
|
+
domain (~> 1.0)
|
14
|
+
path (1.3.1)
|
15
|
+
rake (10.1.0)
|
16
|
+
rspec (2.14.1)
|
17
|
+
rspec-core (~> 2.14.0)
|
18
|
+
rspec-expectations (~> 2.14.0)
|
19
|
+
rspec-mocks (~> 2.14.0)
|
20
|
+
rspec-core (2.14.4)
|
21
|
+
rspec-expectations (2.14.0)
|
22
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
23
|
+
rspec-mocks (2.14.1)
|
24
|
+
sequel (3.48.0)
|
25
|
+
sexpr (0.5.1)
|
26
|
+
sqlite3 (1.3.7)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
java
|
30
|
+
ruby
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
alf-core (~> 0.13.0)
|
34
|
+
jdbc-sqlite3 (~> 3.7)
|
35
|
+
rake (~> 10.1)
|
36
|
+
rspec (~> 2.14)
|
37
|
+
sequel (~> 3.48)
|
38
|
+
sqlite3 (~> 1.3)
|
data/LICENCE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# The MIT Licence
|
2
|
+
|
3
|
+
Copyright (c) 2012 - Bernard Lambeau
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Alf::Sequel
|
2
|
+
|
3
|
+
[](http://travis-ci.org/alf-tool/alf-sequel)
|
4
|
+
[](https://gemnasium.com/alf-tool/alf-sequel)
|
5
|
+
|
6
|
+
A sequel adapter for alf
|
7
|
+
|
8
|
+
## Links
|
9
|
+
|
10
|
+
http://github.com/alf-tool/alf
|
11
|
+
http://github.com/alf-tool/alf-sequel
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
class Adapter < Alf::Adapter
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def recognizes?(conn_spec)
|
8
|
+
case conn_spec
|
9
|
+
when ::Sequel::Database
|
10
|
+
true
|
11
|
+
when String
|
12
|
+
require 'uri'
|
13
|
+
uri = URI::parse(conn_spec) rescue nil
|
14
|
+
(uri && uri.scheme) or looks_a_sqlite_file?(conn_spec)
|
15
|
+
when Hash
|
16
|
+
conn_spec = Tools.symbolize_keys(conn_spec)
|
17
|
+
conn_spec[:adapter] && conn_spec[:database]
|
18
|
+
else
|
19
|
+
looks_a_sqlite_file?(conn_spec)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns true if `f` looks like a sqlite file
|
24
|
+
def looks_a_sqlite_file?(f)
|
25
|
+
return false unless Path.like?(f)
|
26
|
+
path = Path(f)
|
27
|
+
path.parent.directory? and ['db', 'sqlite', 'sqlite3'].include?(path.ext)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sqlite_protocol
|
31
|
+
defined?(JRUBY_VERSION) ? "jdbc:sqlite" : "sqlite"
|
32
|
+
end
|
33
|
+
|
34
|
+
def sequel_db(conn_spec)
|
35
|
+
require 'sequel' unless defined?(::Sequel)
|
36
|
+
case conn_spec
|
37
|
+
when ::Sequel::Database
|
38
|
+
conn_spec
|
39
|
+
when String, Path
|
40
|
+
conn_spec = "#{sqlite_protocol}://#{conn_spec}" if looks_a_sqlite_file?(conn_spec)
|
41
|
+
::Sequel.connect(conn_spec)
|
42
|
+
else
|
43
|
+
raise ArgumentError, "Unrecognized connection specification `#{conn_spec.inspect}`"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end # class << self
|
48
|
+
|
49
|
+
# Returns a low-level connection on this adapter
|
50
|
+
def connection
|
51
|
+
Connection.new(conn_spec)
|
52
|
+
end
|
53
|
+
|
54
|
+
::Alf::Adapter.register(:sequel, self)
|
55
|
+
end # class Adapter
|
56
|
+
end # module Sequel
|
57
|
+
end # module Alf
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
class Cog
|
4
|
+
include Engine::Cog
|
5
|
+
|
6
|
+
def initialize(connection, opts)
|
7
|
+
@connection = connection
|
8
|
+
@opts = opts
|
9
|
+
end
|
10
|
+
attr_reader :connection, :opts
|
11
|
+
|
12
|
+
def as; opts[:as]; end
|
13
|
+
def dataset; opts[:dataset]; end
|
14
|
+
|
15
|
+
### Cog
|
16
|
+
|
17
|
+
def to_relation
|
18
|
+
Relation.coerce(to_a)
|
19
|
+
end
|
20
|
+
|
21
|
+
def each
|
22
|
+
dataset.each(&Proc.new)
|
23
|
+
end
|
24
|
+
|
25
|
+
### Delegation to Dataset, that is, facade over ::Sequel itself
|
26
|
+
|
27
|
+
def select(attrs)
|
28
|
+
branch dataset: dataset.select(*qualify(attrs))
|
29
|
+
end
|
30
|
+
|
31
|
+
def rename(attrs, opts)
|
32
|
+
branch dataset: dataset.select(*qualify(attrs)).from_self(opts),
|
33
|
+
as: opts[:alias]
|
34
|
+
end
|
35
|
+
|
36
|
+
def distinct(*args, &bl)
|
37
|
+
branch dataset: dataset.distinct(*args, &bl)
|
38
|
+
end
|
39
|
+
|
40
|
+
def order(*args, &bl)
|
41
|
+
branch dataset: dataset.order(*args, &bl)
|
42
|
+
end
|
43
|
+
|
44
|
+
def filter(*args, &bl)
|
45
|
+
branch dataset: dataset.filter(*args, &bl)
|
46
|
+
end
|
47
|
+
|
48
|
+
def intersect(other, opts={})
|
49
|
+
branch dataset: dataset.intersect(other.dataset, opts),
|
50
|
+
as: opts[:alias]
|
51
|
+
end
|
52
|
+
|
53
|
+
def join(other, cols, opts={})
|
54
|
+
join = dataset.inner_join(other.dataset, cols, :table_alias => opts[:alias])
|
55
|
+
branch dataset: join.from_self(opts),
|
56
|
+
as: opts[:alias]
|
57
|
+
end
|
58
|
+
|
59
|
+
def union(other, opts={})
|
60
|
+
branch dataset: dataset.union(other.dataset, opts),
|
61
|
+
as: opts[:alias]
|
62
|
+
end
|
63
|
+
|
64
|
+
### compilation tools
|
65
|
+
|
66
|
+
def sql
|
67
|
+
dataset.sql
|
68
|
+
end
|
69
|
+
|
70
|
+
def qualify(attributes)
|
71
|
+
return attributes unless as
|
72
|
+
case attributes
|
73
|
+
when Symbol
|
74
|
+
::Sequel.qualify(as, attributes)
|
75
|
+
when Hash
|
76
|
+
attributes.map{|k,v| ::Sequel.as(::Sequel.qualify(as, k), v) }
|
77
|
+
else
|
78
|
+
attributes.map{|a| ::Sequel.qualify(as, a)}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def branch(opts = {})
|
83
|
+
Cog.new connection, self.opts.merge(opts)
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_s
|
87
|
+
"Alf::Sequel::Cog|#{sql}"
|
88
|
+
end
|
89
|
+
|
90
|
+
end # class Operand
|
91
|
+
end # module Sequel
|
92
|
+
end # module Alf
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
class Compiler
|
4
|
+
class Predicate < Sexpr::Processor
|
5
|
+
|
6
|
+
def call(predicate)
|
7
|
+
super(predicate.expr)
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_missing(sexpr)
|
11
|
+
throw :pass
|
12
|
+
end
|
13
|
+
alias :on_native :on_missing
|
14
|
+
|
15
|
+
def on_tautology(sexpr)
|
16
|
+
::Sequel::SQL::BooleanConstant.new(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_contradiction(sexpr)
|
20
|
+
::Sequel::SQL::BooleanConstant.new(false)
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_var_ref(sexpr)
|
24
|
+
if qualifier = options[:qualifier]
|
25
|
+
::Sequel.qualify(qualifier, sexpr.last)
|
26
|
+
else
|
27
|
+
::Sequel.expr(sexpr.last)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_literal(sexpr)
|
32
|
+
sexpr.last.nil? ? nil : ::Sequel.expr(sexpr.last)
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_eq(sexpr)
|
36
|
+
left, right = apply(sexpr.left), apply(sexpr.right)
|
37
|
+
::Sequel.expr(left => right)
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_neq(sexpr)
|
41
|
+
left, right = apply(sexpr.left), apply(sexpr.right)
|
42
|
+
~::Sequel.expr(left => right)
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_dyadic_comp(sexpr)
|
46
|
+
left, right = apply(sexpr.left), apply(sexpr.right)
|
47
|
+
left.send(sexpr.operator_symbol, right)
|
48
|
+
end
|
49
|
+
alias :on_lt :on_dyadic_comp
|
50
|
+
alias :on_lte :on_dyadic_comp
|
51
|
+
alias :on_gt :on_dyadic_comp
|
52
|
+
alias :on_gte :on_dyadic_comp
|
53
|
+
|
54
|
+
def on_in(sexpr)
|
55
|
+
left = apply(sexpr.var_ref)
|
56
|
+
::Sequel.expr(left => sexpr.values)
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_not(sexpr)
|
60
|
+
~apply(sexpr.last)
|
61
|
+
end
|
62
|
+
|
63
|
+
def on_and(sexpr)
|
64
|
+
body = sexpr.sexpr_body
|
65
|
+
body[1..-1].inject(apply(body.first)){|f,t| f & apply(t) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_or(sexpr)
|
69
|
+
body = sexpr.sexpr_body
|
70
|
+
body[1..-1].inject(apply(body.first)){|f,t| f | apply(t) }
|
71
|
+
end
|
72
|
+
|
73
|
+
end # class Predicate
|
74
|
+
end # class Compiler
|
75
|
+
end # module Sequel
|
76
|
+
end # module Alf
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
class Compiler < Algebra::Compiler
|
4
|
+
|
5
|
+
def pass(expr)
|
6
|
+
rewrite(expr)
|
7
|
+
end
|
8
|
+
alias :on_missing :pass
|
9
|
+
|
10
|
+
def next_alias
|
11
|
+
@as ||= 0
|
12
|
+
:"t#{@as += 1}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_leaf_operand(expr)
|
16
|
+
if Algebra::Operand::Named===expr
|
17
|
+
expr.connection.cog(expr.name, :alias => next_alias)
|
18
|
+
else
|
19
|
+
expr.to_cog
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
### non relational
|
24
|
+
|
25
|
+
alias :on_autonum :pass
|
26
|
+
alias :on_coerce :pass
|
27
|
+
alias :on_defaults :pass
|
28
|
+
alias :on_generator :pass
|
29
|
+
|
30
|
+
def on_clip(expr)
|
31
|
+
rewrite(expr){|rw|
|
32
|
+
rw.operand.select(expr.stay_attributes)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_compact(expr)
|
37
|
+
rewrite(expr){|rw|
|
38
|
+
rw.operand.distinct
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_sort(expr)
|
43
|
+
rewrite(expr){|rw|
|
44
|
+
operand = rw.operand
|
45
|
+
ordering = expr.ordering.to_a.map{|(col,dir)|
|
46
|
+
::Sequel.send(dir, operand.qualify(col))
|
47
|
+
}
|
48
|
+
operand.order(*ordering)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
### relational
|
53
|
+
|
54
|
+
alias :on_extend :pass
|
55
|
+
alias :on_group :pass
|
56
|
+
alias :on_infer_heading :pass
|
57
|
+
|
58
|
+
def on_intersect(expr)
|
59
|
+
rewrite(expr){|rw|
|
60
|
+
rw.left.intersect(rw.right, :alias => next_alias)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_join(expr)
|
65
|
+
rewrite(expr){|rw|
|
66
|
+
rw.left.join(rw.right, expr.common_attributes.to_a, :alias => next_alias)
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def on_matching(expr)
|
71
|
+
rewrite(expr) do |rw|
|
72
|
+
rw.left.filter(matching2filter(expr, rw))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def on_not_matching(expr)
|
77
|
+
rewrite(expr) do |rw|
|
78
|
+
rw.left.filter(~matching2filter(expr, rw))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def matching2filter(expr, rw)
|
83
|
+
commons = expr.common_attributes.to_a
|
84
|
+
if commons.size==1
|
85
|
+
# (NOT) IN (SELECT ...)
|
86
|
+
pred = ::Alf::Predicate.in(commons.first, rw.right.select(commons).dataset)
|
87
|
+
Predicate.new(:qualifier => rw.left.as).call(pred)
|
88
|
+
elsif commons.size==0
|
89
|
+
# (NOT) EXISTS (SELECT ... no join condition ...)
|
90
|
+
rw.right.dataset.exists
|
91
|
+
else
|
92
|
+
# (NOT) EXISTS (SELECT ...)
|
93
|
+
filter = Hash[rw.left.qualify(commons).zip(rw.right.qualify(commons))]
|
94
|
+
filter = ::Sequel.expr filter
|
95
|
+
filter = rw.right.filter(filter)
|
96
|
+
filter.dataset.exists
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
alias :on_minus :pass
|
101
|
+
|
102
|
+
def on_project(expr)
|
103
|
+
rewrite(expr){|rw|
|
104
|
+
compiled = rw.operand.select(expr.stay_attributes)
|
105
|
+
compiled = compiled.distinct unless key_preserving?(expr){ false }
|
106
|
+
compiled
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
alias :on_quota :pass
|
111
|
+
alias :on_rank :pass
|
112
|
+
|
113
|
+
def on_rename(expr)
|
114
|
+
rewrite(expr){|rw|
|
115
|
+
rw.operand.rename(expr.complete_renaming.to_hash, :alias => next_alias)
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def on_restrict(expr)
|
120
|
+
rewrite(expr){|rw|
|
121
|
+
filter = Predicate.new(:qualifier => rw.operand.as).call(rw.predicate)
|
122
|
+
rw.operand.filter(filter)
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
alias :on_summarize :pass
|
127
|
+
alias :on_ungroup :pass
|
128
|
+
|
129
|
+
def on_union(expr)
|
130
|
+
rewrite(expr){|rw|
|
131
|
+
rw.left.union(rw.right, :alias => next_alias)
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
alias :on_unwrap :pass
|
136
|
+
alias :on_wrap :pass
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def key_preserving?(expr)
|
141
|
+
expr.key_preserving?
|
142
|
+
rescue NotSupportedError
|
143
|
+
block_given? ? yield : raise
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def rewrite(expr)
|
149
|
+
rewrited = copy_and_apply(expr)
|
150
|
+
if block_given? and rewrited.operands.all?{|op| recognized?(op) }
|
151
|
+
catch(:pass){ rewrited = yield(rewrited) }
|
152
|
+
end
|
153
|
+
rewrited = engine.call(rewrited) unless recognized?(rewrited)
|
154
|
+
rewrited
|
155
|
+
end
|
156
|
+
|
157
|
+
def recognized?(op)
|
158
|
+
op.is_a?(Cog)
|
159
|
+
end
|
160
|
+
|
161
|
+
def engine
|
162
|
+
@engine ||= Engine::Compiler.new
|
163
|
+
end
|
164
|
+
|
165
|
+
end # class Compiler
|
166
|
+
end # module Sequel
|
167
|
+
end # module Alf
|
168
|
+
require_relative 'compiler/predicate'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
class Connection
|
4
|
+
module ConnectionMethods
|
5
|
+
|
6
|
+
def connection_uri(with_password = false)
|
7
|
+
if conn_spec.is_a?(Hash)
|
8
|
+
cs = Tuple(self.conn_spec)
|
9
|
+
adapter, host, port, database, user, password = cs.values_at(:adapter, :host, :port, :database, :user, :password)
|
10
|
+
user = "#{user}:#{password}" if user and password and with_password
|
11
|
+
user = "#{user}@" if user
|
12
|
+
host = "localhost" if host.nil? and not(adapter =~ /sqlite/)
|
13
|
+
host = "#{host}:#{port}" if host and port
|
14
|
+
host = "/#{user}#{host}" if host or user
|
15
|
+
"#{adapter}:/#{host}/#{database}"
|
16
|
+
elsif conn_spec.is_a?(String)
|
17
|
+
conn_spec
|
18
|
+
else
|
19
|
+
"Alf::Sequel::Connection(#{conn_spec})"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def ping
|
24
|
+
sequel_db.test_connection
|
25
|
+
end
|
26
|
+
|
27
|
+
def close
|
28
|
+
@sequel_db.disconnect if @sequel_db && @sequel_db != conn_spec
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_sequel_db
|
32
|
+
yield(sequel_db)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Yields a Sequel::Database object
|
38
|
+
def sequel_db
|
39
|
+
@sequel_db ||= Adapter.sequel_db(conn_spec)
|
40
|
+
block_given? ? yield(@sequel_db) : @sequel_db
|
41
|
+
end
|
42
|
+
|
43
|
+
end # module ConnectionMethods
|
44
|
+
end # module Connection
|
45
|
+
end # module Sequel
|
46
|
+
end # module Alf
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
class Connection
|
4
|
+
module SchemaMethods
|
5
|
+
|
6
|
+
def knows?(name)
|
7
|
+
sequel_db.table_exists?(name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def dataset(name)
|
11
|
+
sequel_db[name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def cog(name, opts={})
|
15
|
+
if as = opts[:alias]
|
16
|
+
Cog.new(self, dataset: dataset(:"#{name}___#{as}"), as: as)
|
17
|
+
else
|
18
|
+
Cog.new(self, dataset: dataset(name))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def heading(name)
|
23
|
+
h = {}
|
24
|
+
sequel_db.schema(name).each do |pair|
|
25
|
+
column_name, info = pair
|
26
|
+
h[column_name] = dbtype_to_ruby_type(info)
|
27
|
+
end
|
28
|
+
Heading.new(h)
|
29
|
+
end
|
30
|
+
|
31
|
+
def keys(name)
|
32
|
+
# take the indexes
|
33
|
+
indexes = sequel_db.indexes(name).
|
34
|
+
values.
|
35
|
+
select{|i| i[:unique] == true }.
|
36
|
+
map{|i| AttrList.coerce(i[:columns]) }.
|
37
|
+
sort{|a1, a2| a1.size <=> a2.size}
|
38
|
+
|
39
|
+
# take single keys as well
|
40
|
+
key = sequel_db.schema(name).
|
41
|
+
select{|(colname, colinfo)| colinfo[:primary_key] }.
|
42
|
+
map(&:first)
|
43
|
+
indexes.unshift(AttrList.coerce(key)) unless key.empty?
|
44
|
+
|
45
|
+
Keys.new(indexes)
|
46
|
+
end
|
47
|
+
|
48
|
+
def migrate!(opts)
|
49
|
+
unless f = opts.migrations_folder
|
50
|
+
raise Alf::ConfigError, "Migrations folder not set"
|
51
|
+
end
|
52
|
+
with_sequel_db do |db|
|
53
|
+
::Sequel.extension(:migration)
|
54
|
+
::Sequel::Migrator.apply(db, f)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def dbtype_to_ruby_type(info)
|
61
|
+
return Object unless info[:type]
|
62
|
+
begin
|
63
|
+
Kernel.eval(info[:type].to_s.capitalize)
|
64
|
+
rescue NameError
|
65
|
+
case info[:type]
|
66
|
+
when :datetime then DateTime
|
67
|
+
when :boolean then Alf::Boolean
|
68
|
+
else Object
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end # module SchemaMethods
|
74
|
+
end # module Connection
|
75
|
+
end # module Sequel
|
76
|
+
end # module Alf
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Alf
|
2
|
+
module Sequel
|
3
|
+
class Connection
|
4
|
+
module UpdateMethods
|
5
|
+
|
6
|
+
# Yields the block in a transaction
|
7
|
+
def in_transaction(&bl)
|
8
|
+
sequel_db.transaction(&bl)
|
9
|
+
end
|
10
|
+
|
11
|
+
def lock(name, mode, &bl)
|
12
|
+
with_dataset(name){|ds|
|
13
|
+
if ds.respond_to?(:lock)
|
14
|
+
ds.lock(mode.to_s.upcase, &bl)
|
15
|
+
else
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Inserts `tuples` in the relvar called `name`
|
22
|
+
def insert(name, tuples)
|
23
|
+
insert_uow(name, tuples).run
|
24
|
+
end
|
25
|
+
|
26
|
+
# Delete from the relvar called `name`
|
27
|
+
def delete(name, predicate)
|
28
|
+
delete_uow(name, predicate).run
|
29
|
+
end
|
30
|
+
|
31
|
+
# Updates the relvar called `name`
|
32
|
+
def update(name, updating, predicate)
|
33
|
+
update_uow(name, updating, predicate).run
|
34
|
+
end
|
35
|
+
|
36
|
+
public # should be private
|
37
|
+
|
38
|
+
def with_dataset(name, predicate = nil)
|
39
|
+
ds = name.is_a?(Symbol) ? sequel_db[name] : name
|
40
|
+
if predicate && !predicate.tautology?
|
41
|
+
ds = ds.filter(Compiler::Predicate.call(predicate))
|
42
|
+
end
|
43
|
+
yield(ds) if block_given?
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def insert_uow(name, tuples)
|
49
|
+
UnitOfWork::Insert.new(self, name, tuples)
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete_uow(name, predicate)
|
53
|
+
UnitOfWork::Delete.new(self, name, predicate)
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_uow(name, updating, predicate)
|
57
|
+
UnitOfWork::Update.new(self, name, updating, predicate)
|
58
|
+
end
|
59
|
+
|
60
|
+
end # module UpdateMethods
|
61
|
+
end # module Connection
|
62
|
+
end # module Sequel
|
63
|
+
end # module Alf
|