rdo 0.0.6 → 0.0.7
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/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
|