rdo 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +21 -4
- data/lib/rdo.rb +17 -1
- data/lib/rdo/connection.rb +22 -4
- data/lib/rdo/version.rb +1 -1
- data/spec/rdo/rdo_spec.rb +55 -0
- data/util/macros.h +64 -48
- metadata +4 -2
data/README.md
CHANGED
@@ -37,7 +37,7 @@ conn.close
|
|
37
37
|
## Why your ORM so shit?
|
38
38
|
|
39
39
|
RDO provides access to a number of RDBMS's. It allows you to query using SQL
|
40
|
-
and
|
40
|
+
and other things using DDL, as thinly as is necessary. It is absolutely not,
|
41
41
|
nor is it trying to be an SQL abstraction layer, an ORM or anything of that
|
42
42
|
nature. The intention is to provide a way to allow Ruby developers to write
|
43
43
|
applications that use a database, but don't use an ORM (*scoff!*).
|
@@ -94,26 +94,30 @@ And then execute:
|
|
94
94
|
<th>URI Schemes</th>
|
95
95
|
<th>Gem</th>
|
96
96
|
<th>Author</th>
|
97
|
+
<th>Status</th>
|
97
98
|
</tr>
|
98
99
|
</thead>
|
99
100
|
<tbody>
|
100
101
|
<tr>
|
101
102
|
<th>SQLite</th>
|
102
|
-
<td>sqlite</td>
|
103
|
+
<td>sqlite, sqlite3</td>
|
103
104
|
<td><a href="https://github.com/d11wtq/rdo-sqlite">rdo-sqlite</a></td>
|
104
105
|
<td><a href="https://github.com/d11wtq">d11wtq</a></td>
|
106
|
+
<td>Published</td>
|
105
107
|
</tr>
|
106
108
|
<tr>
|
107
109
|
<th>PostgreSQL</th>
|
108
110
|
<td>postgresql, postgres</td>
|
109
111
|
<td><a href="https://github.com/d11wtq/rdo-postgres">rdo-postgres</a></td>
|
110
112
|
<td><a href="https://github.com/d11wtq">d11wtq</a></td>
|
113
|
+
<td>Published</td>
|
111
114
|
</tr>
|
112
115
|
<tr>
|
113
116
|
<th>MySQL</th>
|
114
117
|
<td>mysql</td>
|
115
118
|
<td><a href="https://github.com/d11wtq/rdo-mysql">rdo-mysql</a></td>
|
116
119
|
<td><a href="https://github.com/d11wtq">d11wtq</a></td>
|
120
|
+
<td>Pending development</td>
|
117
121
|
</tr>
|
118
122
|
</tbody>
|
119
123
|
</table>
|
@@ -137,6 +141,8 @@ conn = RDO.connect("postgresql://user:pass@host:port/db_name?encoding=utf-8")
|
|
137
141
|
p conn.open? #=> true
|
138
142
|
```
|
139
143
|
|
144
|
+
For semantic reasons, #connect is aliased to #open.
|
145
|
+
|
140
146
|
If it is not possible to establish a connection an RDO::Exception is raised,
|
141
147
|
which should provide any reason given by the DBMS.
|
142
148
|
|
@@ -146,8 +152,7 @@ RDO will disconnect automatically when the connection is garbage-collected,
|
|
146
152
|
or when the program exits, but if you need to disconnect explicitly,
|
147
153
|
call #close. It is safe to call this even if the connection is already closed.
|
148
154
|
|
149
|
-
|
150
|
-
child processes.
|
155
|
+
If you have called #close, say before forking, call #open to re-connect.
|
151
156
|
|
152
157
|
``` ruby
|
153
158
|
conn.close
|
@@ -157,6 +162,18 @@ conn.open
|
|
157
162
|
p conn.open? #=> true
|
158
163
|
```
|
159
164
|
|
165
|
+
### One-time use connections
|
166
|
+
|
167
|
+
If you pass a block to RDO.connect, RDO yields the connection into the block,
|
168
|
+
returns the result of the block, the closes the connection.
|
169
|
+
|
170
|
+
``` ruby
|
171
|
+
puts RDO.open("sqlite:some.db") do |c|
|
172
|
+
c.execute("SELECT value FROM config WHERE name = ?", "api_key").first_value
|
173
|
+
end
|
174
|
+
# => "EXAMPLE_KEY"
|
175
|
+
```
|
176
|
+
|
160
177
|
### Performing non-read commands
|
161
178
|
|
162
179
|
All SQL and DDL (Data Definition Language) is executed with #execute, which
|
data/lib/rdo.rb
CHANGED
@@ -17,16 +17,32 @@ require "rdo/util"
|
|
17
17
|
module RDO
|
18
18
|
class << self
|
19
19
|
# Establish a connection to the RDBMS.
|
20
|
+
# The connection will be returned open.
|
20
21
|
#
|
21
22
|
# The needed driver must be loaded before calling this.
|
22
23
|
#
|
24
|
+
# If a block is given, the connection is passed to the block and then
|
25
|
+
# closed at the end of the block, before this method finally returns
|
26
|
+
# the result of the block.
|
27
|
+
#
|
23
28
|
# @param [Object] options
|
24
29
|
# either a connection URI string, or an option Hash
|
25
30
|
#
|
26
31
|
# @return [Connection]
|
27
32
|
# a Connection for the required driver
|
28
33
|
def connect(options)
|
29
|
-
|
34
|
+
if block_given?
|
35
|
+
begin
|
36
|
+
c = Connection.new(options)
|
37
|
+
yield c
|
38
|
+
ensure
|
39
|
+
c.close unless c.nil?
|
40
|
+
end
|
41
|
+
else
|
42
|
+
Connection.new(options)
|
43
|
+
end
|
30
44
|
end
|
45
|
+
|
46
|
+
alias_method :open, :connect
|
31
47
|
end
|
32
48
|
end
|
data/lib/rdo/connection.rb
CHANGED
@@ -92,20 +92,38 @@ module RDO
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def parse_connection_uri(str)
|
95
|
-
uri =
|
95
|
+
uri = # handle e.g. sqlite: and sqlite:// (empty host and path)
|
96
|
+
if str =~ %r{\A[a-z0-9_\+-]+:\Z}i
|
97
|
+
URI.parse(str.to_s + "//rdo-spoof").tap{|u| u.host = nil}
|
98
|
+
elsif str =~ %r{\A[a-z0-9_\+-]+://\Z}i
|
99
|
+
URI.parse(str.to_s + "rdo-spoof").tap{|u| u.host = nil}
|
100
|
+
else
|
101
|
+
URI.parse(str.to_s)
|
102
|
+
end
|
103
|
+
|
96
104
|
normalize_options(
|
97
105
|
{
|
98
106
|
driver: uri.scheme,
|
99
107
|
host: uri.host,
|
100
108
|
port: uri.port,
|
101
|
-
path: uri
|
102
|
-
database: uri.
|
109
|
+
path: extract_uri_path(uri),
|
110
|
+
database: extract_uri_path(uri).to_s.sub("/", ""),
|
103
111
|
user: uri.user,
|
104
112
|
password: uri.password
|
105
|
-
}.merge(parse_query_string(uri
|
113
|
+
}.merge(parse_query_string(extract_uri_query(uri)))
|
106
114
|
)
|
107
115
|
end
|
108
116
|
|
117
|
+
def extract_uri_path(uri)
|
118
|
+
return uri.path unless uri.opaque
|
119
|
+
uri.opaque.sub(/\?.*\Z/, "")
|
120
|
+
end
|
121
|
+
|
122
|
+
def extract_uri_query(uri)
|
123
|
+
return uri.query unless uri.opaque
|
124
|
+
uri.opaque.sub(/\A.*?\?/, "")
|
125
|
+
end
|
126
|
+
|
109
127
|
def parse_query_string(str)
|
110
128
|
str.nil? ? {} : Hash[CGI.parse(str).map{|k,v| [k, v.size == 1 ? v.first : v]}]
|
111
129
|
end
|
data/lib/rdo/version.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RDO do
|
4
|
+
let(:driver_class) { stub(new: driver) }
|
5
|
+
let(:driver) { stub(:driver, open: true, close: true) }
|
6
|
+
|
7
|
+
before(:each) { RDO::Connection.register_driver(:test, driver_class) }
|
8
|
+
|
9
|
+
describe ".connect" do
|
10
|
+
it "returns a connection for the given driver" do
|
11
|
+
RDO.connect("test://whatever").should be_a_kind_of(RDO::Connection)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "opens the connection" do
|
15
|
+
driver.should_receive(:open).and_return(true)
|
16
|
+
RDO.connect("test://whatever")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "is aliased as .open" do
|
20
|
+
RDO.open("test://whatever").should be_a_kind_of(RDO::Connection)
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when given a block" do
|
24
|
+
it "yields the connection" do
|
25
|
+
conn = nil
|
26
|
+
RDO.open("test://whatever") { |c| conn = c }
|
27
|
+
conn.should be_a_kind_of(RDO::Connection)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "opens the connection" do
|
31
|
+
driver.should_receive(:open).and_return(true)
|
32
|
+
RDO.open("test://whatever") { |c| }
|
33
|
+
end
|
34
|
+
|
35
|
+
it "closes the connection" do
|
36
|
+
driver.should_receive(:close).and_return(true)
|
37
|
+
RDO.open("test://whatever") { |c| }
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns the result of the block" do
|
41
|
+
RDO.open("test://whatever"){ |c| "test" }.should == "test"
|
42
|
+
end
|
43
|
+
|
44
|
+
context "on error in block" do
|
45
|
+
it "still closes the connection" do
|
46
|
+
driver.should_receive(:close).and_return(true)
|
47
|
+
begin
|
48
|
+
RDO.open("test://whatever") { |c| raise "Blarg" }
|
49
|
+
rescue
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/util/macros.h
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* RDO
|
2
|
+
* RDO—Ruby Data Objects.
|
3
3
|
* Copyright © 2012 Chris Corbyn.
|
4
4
|
*
|
5
5
|
* See LICENSE file for details.
|
@@ -18,6 +18,52 @@
|
|
18
18
|
* --------------------------------------------------------------------------
|
19
19
|
*/
|
20
20
|
|
21
|
+
#include <ruby.h>
|
22
|
+
#include <ruby/encoding.h>
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Convenience to call #to_s on any Ruby object.
|
26
|
+
*/
|
27
|
+
#define RDO_OBJ_TO_S(obj) (rb_funcall(obj, rb_intern("to_s"), 0))
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Raise an RDO::Exception with the given msg format and any number of parameters.
|
31
|
+
*
|
32
|
+
* @param (char *) msg
|
33
|
+
* a format string passed to rb_raise()
|
34
|
+
*
|
35
|
+
* @param (void *) ...
|
36
|
+
* args used to interpolate the error message
|
37
|
+
*/
|
38
|
+
#define RDO_ERROR(...) (rb_raise(rb_path2class("RDO::Exception"), __VA_ARGS__))
|
39
|
+
|
40
|
+
/**
|
41
|
+
* Factory to return a new RDO::Result for an Enumerable object of tuples.
|
42
|
+
*
|
43
|
+
* @param VALUE (Enumerable) tuples
|
44
|
+
* an object that knows how to iterate all tuples
|
45
|
+
*
|
46
|
+
* @param VALUE (Hash)
|
47
|
+
* an optional hash of query info.
|
48
|
+
*
|
49
|
+
* @return VALUE (RDO::Result)
|
50
|
+
* a new Result object
|
51
|
+
*/
|
52
|
+
#define RDO_RESULT(tuples, info) \
|
53
|
+
(rb_funcall(rb_path2class("RDO::Result"), rb_intern("new"), 2, tuples, info))
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Wrap the given StatementExecutor in a RDO::Statement.
|
57
|
+
*
|
58
|
+
* @param VALUE
|
59
|
+
* any object that responds to #command and #execute
|
60
|
+
*
|
61
|
+
* @return VALUE
|
62
|
+
* an RDO::Statement
|
63
|
+
*/
|
64
|
+
#define RDO_STATEMENT(executor) \
|
65
|
+
(rb_funcall(rb_path2class("RDO::Statement"), rb_intern("new"), 1, executor))
|
66
|
+
|
21
67
|
/**
|
22
68
|
* Convert a C string to a ruby String.
|
23
69
|
*
|
@@ -30,9 +76,8 @@
|
|
30
76
|
* @return VALUE (String)
|
31
77
|
* a Ruby String
|
32
78
|
*/
|
33
|
-
#define RDO_STRING(s, len, enc)
|
34
|
-
|
35
|
-
)
|
79
|
+
#define RDO_STRING(s, len, enc) \
|
80
|
+
(rb_enc_associate_index(rb_str_new(s, len), enc > 0 ? enc : 0))
|
36
81
|
|
37
82
|
/**
|
38
83
|
* Convert a C string to a ruby String, assuming possible NULL bytes.
|
@@ -64,11 +109,9 @@
|
|
64
109
|
* @return VALUE (Float)
|
65
110
|
* a ruby Float
|
66
111
|
*/
|
67
|
-
#define RDO_FLOAT(s)
|
68
|
-
|
69
|
-
|
70
|
-
rb_str_new2(s)) \
|
71
|
-
)
|
112
|
+
#define RDO_FLOAT(s) \
|
113
|
+
(rb_funcall(rb_path2class("RDO::Util"), \
|
114
|
+
rb_intern("float"), 1, rb_str_new2(s)))
|
72
115
|
|
73
116
|
/**
|
74
117
|
* Convert a C string representing a precision decimal into a BigDecimal.
|
@@ -83,11 +126,9 @@
|
|
83
126
|
* RDO_DECIMAL("1.234")
|
84
127
|
* => #<BigDecimal:7feb42b2b6e8,'0.1234E1',18(18)>
|
85
128
|
*/
|
86
|
-
#define RDO_DECIMAL(s)
|
87
|
-
|
88
|
-
|
89
|
-
rb_str_new2(s)) \
|
90
|
-
)
|
129
|
+
#define RDO_DECIMAL(s) \
|
130
|
+
(rb_funcall(rb_path2class("RDO::Util"), \
|
131
|
+
rb_intern("decimal"), 1, rb_str_new2(s)))
|
91
132
|
|
92
133
|
/**
|
93
134
|
* Convert a C string representing a date into a Date.
|
@@ -102,11 +143,9 @@
|
|
102
143
|
* RDO_DATE("431-09-22 BC")
|
103
144
|
* #<Date: -0430-09-22 ((1564265j,0s,0n),+0s,2299161j)>
|
104
145
|
*/
|
105
|
-
#define RDO_DATE(s)
|
106
|
-
|
107
|
-
|
108
|
-
rb_str_new2(s)) \
|
109
|
-
)
|
146
|
+
#define RDO_DATE(s) \
|
147
|
+
(rb_funcall(rb_path2class("RDO::Util"), \
|
148
|
+
rb_intern("date"), 1, rb_str_new2(s)))
|
110
149
|
|
111
150
|
/**
|
112
151
|
* Convert a C string representing a date & time with no time zone into a DateTime.
|
@@ -121,11 +160,9 @@
|
|
121
160
|
* RDO_DATE_TIME_WITHOUT_ZONE("2012-09-22 04:36:12")
|
122
161
|
* #<DateTime: 2012-09-22T04:36:12+10:00 ((2456192j,66972s,0n),+36000s,2299161j)>
|
123
162
|
*/
|
124
|
-
#define RDO_DATE_TIME_WITHOUT_ZONE(s)
|
125
|
-
|
126
|
-
|
127
|
-
rb_str_new2(s)) \
|
128
|
-
)
|
163
|
+
#define RDO_DATE_TIME_WITHOUT_ZONE(s) \
|
164
|
+
(rb_funcall(rb_path2class("RDO::Util"), \
|
165
|
+
rb_intern("date_time_without_zone"), 1, rb_str_new2(s)))
|
129
166
|
|
130
167
|
/**
|
131
168
|
* Convert a C string representing a date & time that includes a time zone into a DateTime.
|
@@ -140,11 +177,9 @@
|
|
140
177
|
* RDO_DATE_TIME_WITHOUT_ZONE("2012-09-22 04:36:12+10:00")
|
141
178
|
* #<DateTime: 2012-09-22T04:36:12+10:00 ((2456192j,66972s,0n),+36000s,2299161j)>
|
142
179
|
*/
|
143
|
-
#define RDO_DATE_TIME_WITH_ZONE(s)
|
144
|
-
|
145
|
-
|
146
|
-
rb_str_new2(s)) \
|
147
|
-
)
|
180
|
+
#define RDO_DATE_TIME_WITH_ZONE(s) \
|
181
|
+
(rb_funcall(rb_path2class("RDO::Util"), \
|
182
|
+
rb_intern("date_time_with_zone"), 1, rb_str_new2(s)))
|
148
183
|
|
149
184
|
/**
|
150
185
|
* Convert a boolean string to TrueClass/FalseClass.
|
@@ -156,22 +191,3 @@
|
|
156
191
|
* the boolean representation
|
157
192
|
*/
|
158
193
|
#define RDO_BOOL(s) ((s[0] == 't') ? Qtrue : Qfalse)
|
159
|
-
|
160
|
-
/**
|
161
|
-
* Wrap the given StatementExecutor in a RDO::Statement.
|
162
|
-
*
|
163
|
-
* @param VALUE
|
164
|
-
* any object that responds to #command and #execute
|
165
|
-
*
|
166
|
-
* @return VALUE
|
167
|
-
* an RDO::Statement
|
168
|
-
*/
|
169
|
-
#define RDO_STATEMENT(executor) ( \
|
170
|
-
rb_funcall(rb_path2class("RDO::Statement"), \
|
171
|
-
rb_intern("new"), 1, executor) \
|
172
|
-
)
|
173
|
-
|
174
|
-
/**
|
175
|
-
* Convenience to call #to_s on any Ruby object.
|
176
|
-
*/
|
177
|
-
#define RDO_OBJ_TO_S(obj) (rb_funcall(obj, rb_intern("to_s"), 0))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- spec/rdo/connection_spec.rb
|
71
71
|
- spec/rdo/driver_spec.rb
|
72
72
|
- spec/rdo/emulated_statements_spec.rb
|
73
|
+
- spec/rdo/rdo_spec.rb
|
73
74
|
- spec/rdo/result_spec.rb
|
74
75
|
- spec/rdo/statement_spec.rb
|
75
76
|
- spec/rdo/util_spec.rb
|
@@ -105,6 +106,7 @@ test_files:
|
|
105
106
|
- spec/rdo/connection_spec.rb
|
106
107
|
- spec/rdo/driver_spec.rb
|
107
108
|
- spec/rdo/emulated_statements_spec.rb
|
109
|
+
- spec/rdo/rdo_spec.rb
|
108
110
|
- spec/rdo/result_spec.rb
|
109
111
|
- spec/rdo/statement_spec.rb
|
110
112
|
- spec/rdo/util_spec.rb
|