sequel 0.4.0 → 0.4.1
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 +4 -0
- data/README +1 -6
- data/Rakefile +1 -1
- data/bin/sequel +1 -3
- data/lib/sequel.rb +18 -1
- data/lib/sequel/adapters/ado.rb +104 -0
- data/lib/sequel/adapters/db2.rb +160 -0
- data/lib/sequel/adapters/dbi.rb +130 -0
- data/lib/sequel/adapters/informix.rb +78 -0
- data/lib/sequel/adapters/mysql.rb +256 -0
- data/lib/sequel/adapters/odbc.rb +144 -0
- data/lib/sequel/adapters/oracle.rb +109 -0
- data/lib/sequel/adapters/postgres.rb +507 -0
- data/lib/sequel/adapters/sqlite.rb +186 -0
- data/lib/sequel/ado.rb +2 -104
- data/lib/{sequel-core → sequel}/array_keys.rb +0 -0
- data/lib/{sequel-core → sequel}/connection_pool.rb +0 -0
- data/lib/{sequel-core → sequel}/core_ext.rb +0 -0
- data/lib/{sequel-core → sequel}/core_sql.rb +0 -0
- data/lib/{sequel-core → sequel}/database.rb +10 -20
- data/lib/{sequel-core → sequel}/dataset.rb +0 -0
- data/lib/{sequel-core → sequel}/dataset/convenience.rb +0 -0
- data/lib/{sequel-core → sequel}/dataset/sequelizer.rb +0 -0
- data/lib/{sequel-core → sequel}/dataset/sql.rb +0 -0
- data/lib/sequel/db2.rb +2 -160
- data/lib/sequel/dbi.rb +2 -130
- data/lib/{sequel-core → sequel}/error.rb +0 -0
- data/lib/sequel/informix.rb +2 -78
- data/lib/{sequel-core → sequel}/migration.rb +0 -0
- data/lib/{sequel-core → sequel}/model.rb +0 -0
- data/lib/{sequel-core → sequel}/model/base.rb +0 -0
- data/lib/{sequel-core → sequel}/model/caching.rb +0 -0
- data/lib/{sequel-core → sequel}/model/hooks.rb +0 -0
- data/lib/{sequel-core → sequel}/model/record.rb +0 -0
- data/lib/{sequel-core → sequel}/model/relations.rb +0 -0
- data/lib/{sequel-core → sequel}/model/schema.rb +0 -0
- data/lib/sequel/mysql.rb +2 -256
- data/lib/sequel/odbc.rb +2 -144
- data/lib/sequel/oracle.rb +2 -109
- data/lib/sequel/postgres.rb +2 -507
- data/lib/{sequel-core → sequel}/pretty_table.rb +0 -0
- data/lib/{sequel-core → sequel}/schema.rb +0 -0
- data/lib/{sequel-core → sequel}/schema/schema_generator.rb +0 -0
- data/lib/{sequel-core → sequel}/schema/schema_sql.rb +0 -0
- data/lib/sequel/sqlite.rb +2 -186
- data/lib/{sequel-core → sequel}/worker.rb +0 -0
- data/spec/database_spec.rb +7 -9
- metadata +39 -29
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -79,14 +79,9 @@ Much of Sequel is still undocumented (especially the part relating to model clas
|
|
79
79
|
|
80
80
|
=== Connecting to a database
|
81
81
|
|
82
|
-
Before connecting to a database, you should require the corresponding adaptor, for example:
|
83
|
-
|
84
|
-
require 'sequel/sqlite'
|
85
|
-
|
86
|
-
Note: you don't need to require 'sequel' separately before that, as each adapter requires 'sequel' if it hasn't yet been required.
|
87
|
-
|
88
82
|
To connect to a database you simply provide Sequel with a URL:
|
89
83
|
|
84
|
+
require 'sequel'
|
90
85
|
DB = Sequel.open 'sqlite:///blog.db'
|
91
86
|
|
92
87
|
The connection URL can also include such stuff as the user name and password:
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
NAME = "sequel"
|
9
|
-
VERS = "0.4.
|
9
|
+
VERS = "0.4.1"
|
10
10
|
CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
|
11
11
|
RDOC_OPTS = ['--quiet', '--title', "Sequel: Concise ORM for Ruby",
|
12
12
|
"--opname", "index.html",
|
data/bin/sequel
CHANGED
@@ -22,8 +22,7 @@ if db.nil? || db.empty?
|
|
22
22
|
end
|
23
23
|
|
24
24
|
begin
|
25
|
-
|
26
|
-
require File.join('sequel', scheme)
|
25
|
+
DB = Sequel.connect db
|
27
26
|
rescue LoadError => e
|
28
27
|
puts "Failed to load #{scheme} adapter: #{e.message}"
|
29
28
|
exit
|
@@ -32,7 +31,6 @@ rescue => e
|
|
32
31
|
exit
|
33
32
|
end
|
34
33
|
|
35
|
-
DB = Sequel.connect db
|
36
34
|
begin
|
37
35
|
DB.test_connection
|
38
36
|
rescue => e
|
data/lib/sequel.rb
CHANGED
@@ -6,7 +6,7 @@ files = %w[
|
|
6
6
|
core_ext core_sql array_keys error connection_pool pretty_table
|
7
7
|
dataset migration model schema database worker
|
8
8
|
]
|
9
|
-
dir = File.join(File.dirname(__FILE__), 'sequel
|
9
|
+
dir = File.join(File.dirname(__FILE__), 'sequel')
|
10
10
|
files.each {|f| require(File.join(dir, f))}
|
11
11
|
|
12
12
|
module Sequel #:nodoc:
|
@@ -29,6 +29,23 @@ module Sequel #:nodoc:
|
|
29
29
|
def single_threaded=(value)
|
30
30
|
Database.single_threaded = value
|
31
31
|
end
|
32
|
+
|
33
|
+
def method_missing(m, *args)
|
34
|
+
c = Database.adapter_class(m)
|
35
|
+
begin
|
36
|
+
case args.size
|
37
|
+
when 1: # Sequel.dbi(db_name)
|
38
|
+
opts = {:database => args[0]}
|
39
|
+
when 0 # Sequel.dbi
|
40
|
+
opts = {}
|
41
|
+
else # Sequel.dbi(db_name, opts)
|
42
|
+
opts = args[1].merge(:database => args[0])
|
43
|
+
end
|
44
|
+
rescue
|
45
|
+
raise SequelError, "Invalid parameters specified"
|
46
|
+
end
|
47
|
+
c.new(opts)
|
48
|
+
end
|
32
49
|
end
|
33
50
|
end
|
34
51
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
if !Object.const_defined?('Sequel')
|
2
|
+
require File.join(File.dirname(__FILE__), '../../sequel')
|
3
|
+
end
|
4
|
+
|
5
|
+
require 'win32ole'
|
6
|
+
|
7
|
+
module Sequel
|
8
|
+
# The ADO adapter provides connectivity to ADO databases in Windows. ADO
|
9
|
+
# databases can be opened using a URL with the ado schema:
|
10
|
+
#
|
11
|
+
# DB = Sequel.open('ado://mydb')
|
12
|
+
#
|
13
|
+
# or using the Sequel.ado method:
|
14
|
+
#
|
15
|
+
# DB = Sequel.ado('mydb')
|
16
|
+
#
|
17
|
+
module ADO
|
18
|
+
class Database < Sequel::Database
|
19
|
+
set_adapter_scheme :ado
|
20
|
+
|
21
|
+
AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
|
22
|
+
|
23
|
+
def auto_increment_sql
|
24
|
+
AUTO_INCREMENT
|
25
|
+
end
|
26
|
+
|
27
|
+
def connect
|
28
|
+
dbname = @opts[:database]
|
29
|
+
handle = WIN32OLE.new('ADODB.Connection')
|
30
|
+
handle.Open(dbname)
|
31
|
+
handle
|
32
|
+
end
|
33
|
+
|
34
|
+
def disconnect
|
35
|
+
# how do we disconnect? couldn't find anything in the docs
|
36
|
+
end
|
37
|
+
|
38
|
+
def dataset(opts = nil)
|
39
|
+
ADO::Dataset.new(self, opts)
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute(sql)
|
43
|
+
@logger.info(sql) if @logger
|
44
|
+
@pool.hold {|conn| conn.Execute(sql)}
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :do, :execute
|
48
|
+
end
|
49
|
+
|
50
|
+
class Dataset < Sequel::Dataset
|
51
|
+
def literal(v)
|
52
|
+
case v
|
53
|
+
when Time: literal(v.iso8601)
|
54
|
+
else
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def fetch_rows(sql, &block)
|
60
|
+
@db.synchronize do
|
61
|
+
s = @db.execute sql
|
62
|
+
|
63
|
+
@columns = s.Fields.extend(Enumerable).map {|x| x.Name.to_sym}
|
64
|
+
|
65
|
+
s.moveFirst
|
66
|
+
s.getRows.transpose.each {|r| yield hash_row(r)}
|
67
|
+
end
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def hash_row(row)
|
72
|
+
@columns.inject({}) do |m, c|
|
73
|
+
m[c] = row.shift
|
74
|
+
m
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def array_tuples_fetch_rows(sql, &block)
|
79
|
+
@db.synchronize do
|
80
|
+
s = @db.execute sql
|
81
|
+
|
82
|
+
@columns = s.Fields.extend(Enumerable).map {|x| x.Name.to_sym}
|
83
|
+
|
84
|
+
s.moveFirst
|
85
|
+
s.getRows.transpose.each {|r| r.keys = @columns; yield r}
|
86
|
+
end
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
def insert(*values)
|
91
|
+
@db.do insert_sql(*values)
|
92
|
+
end
|
93
|
+
|
94
|
+
def update(values, opts = nil)
|
95
|
+
@db.do update_sql(values, opts)
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def delete(opts = nil)
|
100
|
+
@db.do delete_sql(opts)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
if !Object.const_defined?('Sequel')
|
2
|
+
require File.join(File.dirname(__FILE__), '../../sequel')
|
3
|
+
end
|
4
|
+
|
5
|
+
require 'db2/db2cli'
|
6
|
+
|
7
|
+
module Sequel
|
8
|
+
module DB2
|
9
|
+
class Database < Sequel::Database
|
10
|
+
set_adapter_scheme :db2
|
11
|
+
include DB2CLI
|
12
|
+
|
13
|
+
# AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
|
14
|
+
#
|
15
|
+
# def auto_increment_sql
|
16
|
+
# AUTO_INCREMENT
|
17
|
+
# end
|
18
|
+
|
19
|
+
def check_error(rc, msg)
|
20
|
+
case rc
|
21
|
+
when SQL_SUCCESS, SQL_SUCCESS_WITH_INFO: nil
|
22
|
+
else
|
23
|
+
raise SequelError, msg
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
rc, @@env = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE)
|
28
|
+
check_error(rc, "Could not allocate DB2 environment")
|
29
|
+
|
30
|
+
def connect
|
31
|
+
rc, dbc = SQLAllocHandle(SQL_HANDLE_DBC, @@env)
|
32
|
+
check_error(rc, "Could not allocate database connection")
|
33
|
+
|
34
|
+
rc = SQLConnect(dbc, @opts[:database], @opts[:user], @opts[:password])
|
35
|
+
check_error(rc, "Could not connect to database")
|
36
|
+
|
37
|
+
dbc
|
38
|
+
end
|
39
|
+
|
40
|
+
def disconnect
|
41
|
+
@pool.disconnect do |conn|
|
42
|
+
rc = SQLDisconnect(conn)
|
43
|
+
check_error(rc, "Could not disconnect from database")
|
44
|
+
|
45
|
+
rc = SQLFreeHandle(SQL_HANDLE_DBC, conn)
|
46
|
+
check_error(rc, "Could not free Database handle")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_connection
|
51
|
+
@pool.hold {|conn|}
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
def dataset(opts = nil)
|
56
|
+
DB2::Dataset.new(self, opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute(sql, &block)
|
60
|
+
@logger.info(sql) if @logger
|
61
|
+
@pool.hold do |conn|
|
62
|
+
rc, sth = SQLAllocHandle(SQL_HANDLE_STMT, @handle)
|
63
|
+
check_error(rc, "Could not allocate statement")
|
64
|
+
|
65
|
+
begin
|
66
|
+
rc = SQLExecDirect(sth, sql)
|
67
|
+
check_error(rc, "Could not execute statement")
|
68
|
+
|
69
|
+
block[sth] if block
|
70
|
+
|
71
|
+
rc, rpc = SQLRowCount(sth)
|
72
|
+
check_error(rc, "Could not get RPC")
|
73
|
+
rpc
|
74
|
+
ensure
|
75
|
+
rc = SQLFreeHandle(SQL_HANDLE_STMT, sth)
|
76
|
+
check_error(rc, "Could not free statement")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
alias_method :do, :execute
|
81
|
+
end
|
82
|
+
|
83
|
+
class Dataset < Sequel::Dataset
|
84
|
+
def literal(v)
|
85
|
+
case v
|
86
|
+
when Time: literal(v.iso8601)
|
87
|
+
else
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def fetch_rows(sql, &block)
|
93
|
+
@db.synchronize do
|
94
|
+
@db.execute(sql) do |sth|
|
95
|
+
@column_info = get_column_info(sth)
|
96
|
+
@columns = @column_info.map {|c| c[:name]}
|
97
|
+
while (rc = SQLFetch(@handle)) != SQL_NO_DATA_FOUND
|
98
|
+
@db.check_error(rc, "Could not fetch row")
|
99
|
+
yield hash_row(sth)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
MAX_COL_SIZE = 256
|
107
|
+
|
108
|
+
def get_column_info(sth)
|
109
|
+
rc, column_count = SQLNumResultCols(sth)
|
110
|
+
@db.check_error(rc, "Could not get number of result columns")
|
111
|
+
|
112
|
+
(1..column_count).map do |i|
|
113
|
+
rc, name, buflen, datatype, size, digits, nullable = SQLDescribeCol(sth, i, MAX_COL_SIZE)
|
114
|
+
@b.check_error(rc, "Could not describe column")
|
115
|
+
|
116
|
+
{:name => name, :db2_type => datatype, :precision => size}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def hash_row(sth)
|
121
|
+
row = {}
|
122
|
+
@column_info.each_with_index do |c, i|
|
123
|
+
rc, v = SQLGetData(sth, i+1, c[:db2_type], c[:precision])
|
124
|
+
@db.check_error(rc, "Could not get data")
|
125
|
+
|
126
|
+
@row[c[:name]] = convert_type(v)
|
127
|
+
end
|
128
|
+
row
|
129
|
+
end
|
130
|
+
|
131
|
+
def convert_type(v)
|
132
|
+
case v
|
133
|
+
when DB2CLI::Date
|
134
|
+
DBI::Date.new(v.year, v.month, v.day)
|
135
|
+
when DB2CLI::Time
|
136
|
+
DBI::Time.new(v.hour, v.minute, v.second)
|
137
|
+
when DB2CLI::Timestamp
|
138
|
+
DBI::Timestamp.new(v.year, v.month, v.day,
|
139
|
+
v.hour, v.minute, v.second, v.fraction)
|
140
|
+
when DB2CLI::Null
|
141
|
+
nil
|
142
|
+
else
|
143
|
+
v
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def insert(*values)
|
148
|
+
@db.do insert_sql(*values)
|
149
|
+
end
|
150
|
+
|
151
|
+
def update(values, opts = nil)
|
152
|
+
@db.do update_sql(values, opts)
|
153
|
+
end
|
154
|
+
|
155
|
+
def delete(opts = nil)
|
156
|
+
@db.do delete_sql(opts)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
if !Object.const_defined?('Sequel')
|
2
|
+
require File.join(File.dirname(__FILE__), '../../sequel')
|
3
|
+
end
|
4
|
+
|
5
|
+
require 'dbi'
|
6
|
+
|
7
|
+
module Sequel
|
8
|
+
module DBI
|
9
|
+
class Database < Sequel::Database
|
10
|
+
set_adapter_scheme :dbi
|
11
|
+
|
12
|
+
DBI_ADAPTERS = {
|
13
|
+
:ado => "ADO",
|
14
|
+
:db2 => "DB2",
|
15
|
+
:frontbase => "FrontBase",
|
16
|
+
:interbase => "InterBase",
|
17
|
+
:msql => "Msql",
|
18
|
+
:mysql => "Mysql",
|
19
|
+
:odbc => "ODBC",
|
20
|
+
:oracle => "Oracle",
|
21
|
+
:pg => "Pg",
|
22
|
+
:proxy => "Proxy",
|
23
|
+
:sqlite => "SQLite",
|
24
|
+
:sqlrelay => "SQLRelay"
|
25
|
+
}
|
26
|
+
|
27
|
+
# Converts a uri to an options hash. These options are then passed
|
28
|
+
# to a newly created database object.
|
29
|
+
def self.uri_to_options(uri)
|
30
|
+
database = (uri.path =~ /\/(.*)/) && ($1)
|
31
|
+
if uri.scheme =~ /dbi-(.+)/
|
32
|
+
adapter = DBI_ADAPTERS[$1.to_sym] || $1
|
33
|
+
database = "#{adapter}:#{database}"
|
34
|
+
end
|
35
|
+
{
|
36
|
+
:user => uri.user,
|
37
|
+
:password => uri.password,
|
38
|
+
:host => uri.host,
|
39
|
+
:port => uri.port,
|
40
|
+
:database => database
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def connect
|
46
|
+
dbname = @opts[:database]
|
47
|
+
dbname = 'DBI:' + dbname unless dbname =~ /^DBI:/
|
48
|
+
::DBI.connect(dbname, @opts[:user], @opts[:password])
|
49
|
+
end
|
50
|
+
|
51
|
+
def disconnect
|
52
|
+
@pool.disconnect {|c| c.disconnect}
|
53
|
+
end
|
54
|
+
|
55
|
+
def dataset(opts = nil)
|
56
|
+
DBI::Dataset.new(self, opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute(sql)
|
60
|
+
@logger.info(sql) if @logger
|
61
|
+
@pool.hold do |conn|
|
62
|
+
conn.execute(sql)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def do(sql)
|
67
|
+
@logger.info(sql) if @logger
|
68
|
+
@pool.hold do |conn|
|
69
|
+
conn.do(sql)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Dataset < Sequel::Dataset
|
75
|
+
def literal(v)
|
76
|
+
case v
|
77
|
+
when Time: literal(v.iso8601)
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def fetch_rows(sql, &block)
|
84
|
+
@db.synchronize do
|
85
|
+
s = @db.execute sql
|
86
|
+
begin
|
87
|
+
@columns = s.column_names.map {|c| c.to_sym}
|
88
|
+
s.fetch {|r| yield hash_row(s, r)}
|
89
|
+
ensure
|
90
|
+
s.finish rescue nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
def array_tuples_fetch_rows(sql, &block)
|
97
|
+
@db.synchronize do
|
98
|
+
s = @db.execute sql
|
99
|
+
begin
|
100
|
+
@columns = s.column_names.map {|c| c.to_sym}
|
101
|
+
s.fetch {|r| r.keys = @columns; yield r}
|
102
|
+
ensure
|
103
|
+
s.finish rescue nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
def hash_row(stmt, row)
|
110
|
+
@columns.inject({}) do |m, c|
|
111
|
+
m[c] = row.shift
|
112
|
+
m
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def insert(*values)
|
117
|
+
@db.do insert_sql(*values)
|
118
|
+
end
|
119
|
+
|
120
|
+
def update(values, opts = nil)
|
121
|
+
@db.do update_sql(values, opts)
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
def delete(opts = nil)
|
126
|
+
@db.do delete_sql(opts)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|