rdo 0.0.8 → 0.1.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/README.md +32 -24
- data/lib/rdo.rb +18 -5
- data/lib/rdo/colored_logger.rb +25 -0
- data/lib/rdo/connection.rb +59 -5
- data/lib/rdo/driver.rb +4 -4
- data/lib/rdo/emulated_statement_executor.rb +8 -8
- data/lib/rdo/statement.rb +24 -2
- data/lib/rdo/version.rb +1 -1
- data/spec/rdo/connection_spec.rb +74 -5
- data/spec/rdo/driver_spec.rb +5 -3
- data/spec/rdo/statement_spec.rb +67 -2
- metadata +3 -2
data/README.md
CHANGED
@@ -36,18 +36,18 @@ end
|
|
36
36
|
conn.close
|
37
37
|
```
|
38
38
|
|
39
|
-
##
|
39
|
+
## Strange looking ORM you have there, Sir
|
40
40
|
|
41
|
-
RDO provides access to a number of RDBMS's. It allows you to
|
42
|
-
|
43
|
-
nor is it trying to be an SQL abstraction layer, an ORM or anything of
|
44
|
-
nature. The intention is to provide a way to allow Ruby developers to
|
45
|
-
applications that use a database, but don't use an ORM (*scoff!*).
|
41
|
+
It's not an ORM. RDO provides access to a number of RDBMS's. It allows you to
|
42
|
+
query using pure SQL/DDL commands, as thinly as is necessary. It is absolutely
|
43
|
+
not, nor is it trying to be an SQL abstraction layer, an ORM or anything of
|
44
|
+
that nature. The intention is to provide a way to allow Ruby developers to
|
45
|
+
write applications that use a database, but don't use an ORM (*scoff!*).
|
46
46
|
|
47
47
|
Or perhaps you're actually writing the next kick-ass ORM? Either way, RDO
|
48
48
|
just lets you talk directly to your database.
|
49
49
|
|
50
|
-
##
|
50
|
+
## What's the point?
|
51
51
|
|
52
52
|
Let's face it, we've been writing database applications since the dark ages—
|
53
53
|
it's not that hard. What's lacking from Ruby, however, is any consistency for
|
@@ -56,7 +56,7 @@ serve a different need. [DataMapper](https://github.com/datamapper/dm-core)
|
|
56
56
|
has a layer underneath it called [data_objects](https://github.com/datamapper/do),
|
57
57
|
but it isn't particularly user-friendly when used standalone and it requires
|
58
58
|
jumping through hoops to deal with certain database RDBMS features, such as
|
59
|
-
PostgreSQL bytea fields.
|
59
|
+
PostgreSQL bytea fields (which, in RDO, "just work").
|
60
60
|
|
61
61
|
RDO makes the following things standard:
|
62
62
|
|
@@ -65,11 +65,11 @@ RDO makes the following things standard:
|
|
65
65
|
- **Prepared statements** where possible; emulated where not
|
66
66
|
- **Type-casting** to equivalent Ruby types (e.g. Fixnum, BigDecimal,
|
67
67
|
Float, even Array)
|
68
|
-
- **Buffered result sets** where possible–enumerate millions of rows
|
69
|
-
without memory issues
|
70
68
|
- Access meta data after write operations, with insert IDs standardized
|
71
69
|
- **Use simple core data types** (Hash) for reading values and field names
|
72
70
|
|
71
|
+
Note that data-type support is limited to whatever the DBMS actually supports.
|
72
|
+
|
73
73
|
## Installation
|
74
74
|
|
75
75
|
RDO doesn't do anything by itself. You need to also install the driver for
|
@@ -125,7 +125,10 @@ And then execute:
|
|
125
125
|
<td>mysql</td>
|
126
126
|
<td><a href="https://github.com/d11wtq/rdo-mysql">rdo-mysql</a></td>
|
127
127
|
<td><a href="https://github.com/d11wtq">d11wtq</a></td>
|
128
|
-
<td>
|
128
|
+
<td>
|
129
|
+
<img src="https://secure.travis-ci.org/d11wtq/rdo-mysql.png?branch=master"
|
130
|
+
alt="Build Status" title="Build Status" />
|
131
|
+
</td>
|
129
132
|
</tr>
|
130
133
|
</tbody>
|
131
134
|
</table>
|
@@ -154,6 +157,10 @@ For semantic reasons, #connect is aliased to #open.
|
|
154
157
|
If it is not possible to establish a connection an RDO::Exception is raised,
|
155
158
|
which should provide any reason given by the DBMS.
|
156
159
|
|
160
|
+
You can also pass a block to #connect. This has the same semantics as passing
|
161
|
+
a block to File#open (i.e. it passes itself to the block, returns the value
|
162
|
+
of the block and finally closes the connection).
|
163
|
+
|
157
164
|
### Disconnecting
|
158
165
|
|
159
166
|
RDO will disconnect automatically when the connection is garbage-collected,
|
@@ -170,18 +177,6 @@ conn.open
|
|
170
177
|
p conn.open? #=> true
|
171
178
|
```
|
172
179
|
|
173
|
-
### One-time use connections
|
174
|
-
|
175
|
-
If you pass a block to RDO.connect, RDO yields the connection into the block,
|
176
|
-
returns the result of the block, then closes the connection.
|
177
|
-
|
178
|
-
``` ruby
|
179
|
-
puts RDO.open("sqlite:some.db") do |c|
|
180
|
-
c.execute("SELECT value FROM config WHERE name = ?", "api_key").first_value
|
181
|
-
end
|
182
|
-
# => "EXAMPLE_KEY"
|
183
|
-
```
|
184
|
-
|
185
180
|
### Performing non-read commands
|
186
181
|
|
187
182
|
All SQL and DDL (Data Definition Language) is executed with #execute, which
|
@@ -216,7 +211,7 @@ include any error messaage provided by the DBMS.
|
|
216
211
|
### Performing read queries
|
217
212
|
|
218
213
|
There is no difference in the interface for reads or writes. Just call
|
219
|
-
the #execute method
|
214
|
+
the #execute method in both cases. This always returns a RDO::Result.
|
220
215
|
RDO::Result includes the Enumerable module. Some operations, such as #count
|
221
216
|
may be optimized by the driver.
|
222
217
|
|
@@ -298,6 +293,16 @@ This method returns nil if there are no rows, so if you need to distinguish
|
|
298
293
|
between NULL and no rows, you will need to check the result contents the
|
299
294
|
longer way around.
|
300
295
|
|
296
|
+
### Logging Statements
|
297
|
+
|
298
|
+
A Logger instance (with an interface like that in Ruby stdlib) may be passed
|
299
|
+
in the options when creating a connection. All queries will be logged with
|
300
|
+
DEBUG severity. Errors will be logged with FATAL severity.
|
301
|
+
|
302
|
+
``` ruby
|
303
|
+
RDO.connect("postgres://user:pass@host/db", logger: Logger.new(STDOUT))
|
304
|
+
```
|
305
|
+
|
301
306
|
## Contributing
|
302
307
|
|
303
308
|
If you find a bug in RDO, send a pull request if you think you can fix it.
|
@@ -330,6 +335,9 @@ drivers. If you have written a driver for RDO, please fork this git repo and
|
|
330
335
|
edit this README to list it, then send a pull request. That way others will
|
331
336
|
find it more easily.
|
332
337
|
|
338
|
+
I'm particularly interested in drivers for Oracle and Microsoft SQL Server,
|
339
|
+
though I don't personally use these.
|
340
|
+
|
333
341
|
## Copyright & Licensing
|
334
342
|
|
335
343
|
Written and maintained by Chris Corbyn.
|
data/lib/rdo.rb
CHANGED
@@ -13,6 +13,7 @@ require "rdo/statement"
|
|
13
13
|
require "rdo/emulated_statement_executor"
|
14
14
|
require "rdo/result"
|
15
15
|
require "rdo/util"
|
16
|
+
require "rdo/colored_logger"
|
16
17
|
|
17
18
|
# c extension
|
18
19
|
require "rdo/rdo"
|
@@ -28,24 +29,36 @@ module RDO
|
|
28
29
|
# closed at the end of the block, before this method finally returns
|
29
30
|
# the result of the block.
|
30
31
|
#
|
31
|
-
# @param [Object]
|
32
|
-
# either a connection URI string, or an
|
32
|
+
# @param [Object] uri
|
33
|
+
# either a connection URI string, or an options Hash
|
34
|
+
#
|
35
|
+
# @param [Hash] options
|
36
|
+
# if a URI is provided for the first argument, additional options may
|
37
|
+
# be specified here. These may override settings in the first argument.
|
33
38
|
#
|
34
39
|
# @return [Connection]
|
35
40
|
# a Connection for the required driver
|
36
|
-
def connect(options)
|
41
|
+
def connect(uri, options = {})
|
37
42
|
if block_given?
|
38
43
|
begin
|
39
|
-
c = Connection.new(options)
|
44
|
+
c = Connection.new(uri, options)
|
40
45
|
yield c
|
41
46
|
ensure
|
42
47
|
c.close unless c.nil?
|
43
48
|
end
|
44
49
|
else
|
45
|
-
Connection.new(options)
|
50
|
+
Connection.new(uri, options)
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
49
54
|
alias_method :open, :connect
|
50
55
|
end
|
56
|
+
|
57
|
+
# A suitable NULL device for writing nothing
|
58
|
+
DEV_NULL =
|
59
|
+
if defined? IO::NULL
|
60
|
+
IO::NULL
|
61
|
+
else
|
62
|
+
ENV["OS"] =~ /Windows/ ? "NUL" : "/dev/null"
|
63
|
+
end
|
51
64
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
##
|
2
|
+
# RDO: Ruby Data Objects.
|
3
|
+
# Copyright © 2012 Chris Corbyn.
|
4
|
+
#
|
5
|
+
# See LICENSE file for details.
|
6
|
+
##
|
7
|
+
|
8
|
+
require "logger"
|
9
|
+
|
10
|
+
module RDO
|
11
|
+
# A Logger that outputs using color to highlight errors etc.
|
12
|
+
class ColoredLogger < Logger
|
13
|
+
def initialize(*)
|
14
|
+
super
|
15
|
+
self.formatter =
|
16
|
+
Proc.new do |severity, time, prog, msg|
|
17
|
+
case severity
|
18
|
+
when "DEBUG" then "\033[35mSQL\033[0m \033[36m~\033[0m %s\n" % msg
|
19
|
+
when "FATAL" then "\033[31mERROR ~ %s\033[0m\n" % msg
|
20
|
+
else "%s ~ %s\n" % [severity, msg]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/rdo/connection.rb
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
require "uri"
|
9
9
|
require "cgi"
|
10
|
+
require "logger"
|
10
11
|
require "forwardable"
|
11
12
|
|
12
13
|
module RDO
|
@@ -41,8 +42,11 @@ module RDO
|
|
41
42
|
# Options passed to initialize.
|
42
43
|
attr_reader :options
|
43
44
|
|
45
|
+
# A Logger (from ruby stdlib)
|
46
|
+
attr_accessor :logger
|
47
|
+
|
44
48
|
# Most instance methods are delegated to the driver
|
45
|
-
def_delegators :@driver, :open, :open?, :close, :
|
49
|
+
def_delegators :@driver, :open, :open?, :close, :quote
|
46
50
|
|
47
51
|
# Initialize a new Connection.
|
48
52
|
#
|
@@ -50,13 +54,18 @@ module RDO
|
|
50
54
|
#
|
51
55
|
# If no suitable driver is loaded, an RDO::Exception is raised.
|
52
56
|
#
|
53
|
-
# @param [Object]
|
54
|
-
# either a connection URI, or
|
57
|
+
# @param [Object] uri
|
58
|
+
# either a connection URI string, or an options Hash
|
59
|
+
#
|
60
|
+
# @param [Hash] options
|
61
|
+
# if a URI is provided for the first argument, additional options may
|
62
|
+
# be specified here. These may override settings in the first argument.
|
55
63
|
#
|
56
64
|
# @return [RDO::Connection]
|
57
65
|
# a Connection for the given options
|
58
|
-
def initialize(options)
|
59
|
-
@options = normalize_options(options)
|
66
|
+
def initialize(uri, options = {})
|
67
|
+
@options = normalize_options(uri).merge(normalize_options(options))
|
68
|
+
@logger = @options.fetch(:logger, null_logger)
|
60
69
|
|
61
70
|
unless self.class.drivers.key?(@options[:driver])
|
62
71
|
raise RDO::Exception,
|
@@ -68,6 +77,47 @@ module RDO
|
|
68
77
|
"Unable to connect, but the driver did not provide a reason"
|
69
78
|
end
|
70
79
|
|
80
|
+
# Execute a statement with the configured Driver.
|
81
|
+
#
|
82
|
+
# The statement can either be a read, or a write operation.
|
83
|
+
# Placeholders marked by '?' may be interpolated in the statement, so
|
84
|
+
# that bind parameters can be safely provided.
|
85
|
+
#
|
86
|
+
# Where the RDBMS natively supports bind parameters, this functionality is
|
87
|
+
# used; otherwise, the values are quoted using #quote.
|
88
|
+
#
|
89
|
+
# @param [String] statement
|
90
|
+
# a string of SQL or DDL to be executed
|
91
|
+
#
|
92
|
+
# @param [Array] *bind_values
|
93
|
+
# a list of parameters to substitute in the statement
|
94
|
+
#
|
95
|
+
# @return [Result]
|
96
|
+
# the result of the query
|
97
|
+
def execute(statement, *bind_values)
|
98
|
+
@driver.execute(statement, *bind_values).tap do
|
99
|
+
if logger.debug?
|
100
|
+
logger.debug("#{statement}#{" <Bind: #{bind_values.inspect}>" unless bind_values.empty?}")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
rescue RDO::Exception => e
|
104
|
+
logger.fatal(e.message) if logger.fatal?
|
105
|
+
raise
|
106
|
+
end
|
107
|
+
|
108
|
+
# Create a prepared statement to later be executed with some inputs.
|
109
|
+
#
|
110
|
+
# Not all drivers support this natively, but it is emulated by default.
|
111
|
+
#
|
112
|
+
# @param [String] statement
|
113
|
+
# a string of SQL or DDL, with '?' placeholders for bind parameters
|
114
|
+
#
|
115
|
+
# @return [Statement]
|
116
|
+
# a prepared statement to later be executed
|
117
|
+
def prepare(command)
|
118
|
+
Statement.new(@driver.prepare(command), logger)
|
119
|
+
end
|
120
|
+
|
71
121
|
private
|
72
122
|
|
73
123
|
# Normalizes the given options String or Hash into a Symbol-keyed Hash.
|
@@ -127,5 +177,9 @@ module RDO
|
|
127
177
|
def parse_query_string(str)
|
128
178
|
str.nil? ? {} : Hash[CGI.parse(str).map{|k,v| [k, v.size == 1 ? v.first : v]}]
|
129
179
|
end
|
180
|
+
|
181
|
+
def null_logger
|
182
|
+
Logger.new(RDO::DEV_NULL).tap{|l| l.level = Logger::UNKNOWN}
|
183
|
+
end
|
130
184
|
end
|
131
185
|
end
|
data/lib/rdo/driver.rb
CHANGED
@@ -68,19 +68,19 @@ module RDO
|
|
68
68
|
# @param [String] statement
|
69
69
|
# a string of SQL or DDL, with '?' placeholders for bind parameters
|
70
70
|
#
|
71
|
-
# @return [
|
71
|
+
# @return [StatementExecutor]
|
72
72
|
# a prepared statement to later be executed
|
73
73
|
def prepare(statement)
|
74
|
-
|
74
|
+
emulated_statement_executor(statement)
|
75
75
|
end
|
76
76
|
|
77
77
|
# Execute a statement against the RDBMS.
|
78
78
|
#
|
79
|
-
# The statement can either
|
79
|
+
# The statement can either be a read, or a write operation.
|
80
80
|
# Placeholders marked by '?' may be interpolated in the statement, so
|
81
81
|
# that bind parameters can be safely provided.
|
82
82
|
#
|
83
|
-
# Where the RDBMS natively
|
83
|
+
# Where the RDBMS natively supports bind parameters, this functionality is
|
84
84
|
# used; otherwise, the values are quoted using #quote.
|
85
85
|
#
|
86
86
|
# Drivers MUST override this.
|
@@ -9,20 +9,20 @@ module RDO
|
|
9
9
|
# This StatementExecutor is used as a fallback for prepared statements.
|
10
10
|
#
|
11
11
|
# If a DBMS driver does not implement prepared statements, this is used instead.
|
12
|
-
# The #execute method simply delegates back to the
|
12
|
+
# The #execute method simply delegates back to the driver.
|
13
13
|
class EmulatedStatementExecutor
|
14
14
|
attr_reader :command
|
15
15
|
|
16
|
-
# Initialize a new statement executor for the given
|
16
|
+
# Initialize a new statement executor for the given driver & command.
|
17
17
|
#
|
18
|
-
# @param [RDO::
|
19
|
-
# the
|
18
|
+
# @param [RDO::Driver] driver
|
19
|
+
# the Driver on which #prepare was invoked
|
20
20
|
#
|
21
21
|
# @param [String] command
|
22
22
|
# a string of SQL/DDL to execute
|
23
|
-
def initialize(
|
24
|
-
@
|
25
|
-
@command
|
23
|
+
def initialize(driver, command)
|
24
|
+
@driver = driver
|
25
|
+
@command = command
|
26
26
|
end
|
27
27
|
|
28
28
|
# Execute the command using the given bind values.
|
@@ -30,7 +30,7 @@ module RDO
|
|
30
30
|
# @param [Object...] args
|
31
31
|
# bind parameters to use in place of '?'
|
32
32
|
def execute(*args)
|
33
|
-
@
|
33
|
+
@driver.execute(command, *args)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
data/lib/rdo/statement.rb
CHANGED
@@ -15,14 +15,36 @@ module RDO
|
|
15
15
|
class Statement
|
16
16
|
extend Forwardable
|
17
17
|
|
18
|
-
def_delegators :@executor, :command
|
18
|
+
def_delegators :@executor, :command
|
19
19
|
|
20
20
|
# Initialize a new Statement wrapping the given StatementExecutor.
|
21
21
|
#
|
22
22
|
# @param [Object] executor
|
23
23
|
# any object that responds to #execute, #connection and #command
|
24
|
-
def initialize(executor)
|
24
|
+
def initialize(executor, logger)
|
25
25
|
@executor = executor
|
26
|
+
@logger = logger
|
27
|
+
end
|
28
|
+
|
29
|
+
# Execute the command using the given bind values.
|
30
|
+
#
|
31
|
+
# @param [Object...] args
|
32
|
+
# bind parameters to use in place of '?'
|
33
|
+
def execute(*bind_values)
|
34
|
+
@executor.execute(*bind_values).tap do
|
35
|
+
if logger.debug?
|
36
|
+
logger.debug("#{command}#{" <Bind: #{bind_values.inspect}>" unless bind_values.empty?}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
rescue RDO::Exception => e
|
40
|
+
logger.fatal(e.message) if logger.fatal?
|
41
|
+
raise
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def logger
|
47
|
+
@logger
|
26
48
|
end
|
27
49
|
end
|
28
50
|
end
|
data/lib/rdo/version.rb
CHANGED
data/spec/rdo/connection_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require "logger"
|
2
3
|
|
3
4
|
describe RDO::Connection do
|
4
5
|
after(:each) { RDO::Connection.drivers.clear }
|
@@ -193,16 +194,84 @@ describe RDO::Connection do
|
|
193
194
|
and_return(result)
|
194
195
|
connection.execute("SELECT * FROM bob WHERE ?", true).should == result
|
195
196
|
end
|
197
|
+
|
198
|
+
context "with debug logging" do
|
199
|
+
before(:each) do
|
200
|
+
connection.logger.level = Logger::DEBUG
|
201
|
+
driver.stub(:execute).and_return(result)
|
202
|
+
end
|
203
|
+
|
204
|
+
it "logs the statement" do
|
205
|
+
connection.logger.should_receive(:debug).
|
206
|
+
with(/SELECT \* FROM bob WHERE \?.*?true/)
|
207
|
+
connection.execute("SELECT * FROM bob WHERE ?", true)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context "without debug logging" do
|
212
|
+
before(:each) do
|
213
|
+
connection.logger.level = Logger::INFO
|
214
|
+
driver.stub(:execute).and_return(result)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "does not log the statement" do
|
218
|
+
connection.logger.should_not_receive(:debug)
|
219
|
+
connection.execute("SELECT * FROM bob WHERE ?", true)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
context "when an RDO::Exception occurs" do
|
224
|
+
before(:each) do
|
225
|
+
driver.stub(:execute).and_raise(RDO::Exception.new("some error"))
|
226
|
+
end
|
227
|
+
|
228
|
+
context "with fatal logging" do
|
229
|
+
before(:each) do
|
230
|
+
connection.logger.level = Logger::FATAL
|
231
|
+
end
|
232
|
+
|
233
|
+
it "logs the error" do
|
234
|
+
begin
|
235
|
+
connection.logger.should_receive(:fatal).
|
236
|
+
with(/some error/)
|
237
|
+
connection.execute("SELECT * FROM bob WHERE ?", true)
|
238
|
+
fail("RDO::Exception should be raised")
|
239
|
+
rescue
|
240
|
+
# expected
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context "without debug logging" do
|
246
|
+
before(:each) do
|
247
|
+
connection.logger.level = Logger::UNKNOWN
|
248
|
+
end
|
249
|
+
|
250
|
+
it "does not log the error" do
|
251
|
+
begin
|
252
|
+
connection.logger.should_not_receive(:fatal)
|
253
|
+
connection.execute("SELECT * FROM bob WHERE ?", true)
|
254
|
+
fail("RDO::Exception should be raised")
|
255
|
+
rescue
|
256
|
+
# expected
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
196
261
|
end
|
197
262
|
|
198
263
|
describe "#prepare" do
|
199
|
-
let(:
|
264
|
+
let(:command) { "SELECT * FROM bob WHERE ?" }
|
265
|
+
let(:executor) { stub(command: command) }
|
200
266
|
|
201
267
|
it "delegates to the driver" do
|
202
|
-
driver.should_receive(:prepare).
|
203
|
-
|
204
|
-
|
205
|
-
|
268
|
+
driver.should_receive(:prepare).with(command).and_return(executor)
|
269
|
+
connection.prepare(command).command.should == command
|
270
|
+
end
|
271
|
+
|
272
|
+
it "returns a RDO::Statement" do
|
273
|
+
driver.stub(:prepare).and_return(executor)
|
274
|
+
connection.prepare(command).should be_a_kind_of(RDO::Statement)
|
206
275
|
end
|
207
276
|
end
|
208
277
|
|
data/spec/rdo/driver_spec.rb
CHANGED
@@ -10,12 +10,14 @@ describe RDO::Driver do
|
|
10
10
|
describe "#prepare" do
|
11
11
|
let(:driver) { RDO::DriverWithoutStatements.new }
|
12
12
|
|
13
|
-
it "returns a
|
14
|
-
driver.prepare("SELECT * FROM bob WHERE ?").
|
13
|
+
it "returns a StatementExecutor" do
|
14
|
+
driver.prepare("SELECT * FROM bob WHERE ?").
|
15
|
+
should be_a_kind_of(RDO::EmulatedStatementExecutor)
|
15
16
|
end
|
16
17
|
|
17
18
|
it "has the correct command" do
|
18
|
-
driver.prepare("SELECT * FROM bob WHERE ?").command.
|
19
|
+
driver.prepare("SELECT * FROM bob WHERE ?").command.
|
20
|
+
should == "SELECT * FROM bob WHERE ?"
|
19
21
|
end
|
20
22
|
|
21
23
|
it "calls #execute on the driver" do
|
data/spec/rdo/statement_spec.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require "logger"
|
2
3
|
|
3
4
|
describe RDO::Statement do
|
5
|
+
let(:logger) { Logger.new(RDO::DEV_NULL) }
|
4
6
|
let(:executor) { double(:executor) }
|
5
|
-
let(:stmt) { RDO::Statement.new(executor) }
|
7
|
+
let(:stmt) { RDO::Statement.new(executor, logger) }
|
6
8
|
|
7
9
|
describe "#command" do
|
8
10
|
let(:command) { "SELECT * FROM users" }
|
@@ -14,11 +16,74 @@ describe RDO::Statement do
|
|
14
16
|
end
|
15
17
|
|
16
18
|
describe "#execute" do
|
17
|
-
let(:
|
19
|
+
let(:executor) { double(command: "SELECT * FROM bob WHERE ?", execute: result) }
|
20
|
+
let(:result) { stub(:result) }
|
18
21
|
|
19
22
|
it "delegates to the executor" do
|
20
23
|
executor.should_receive(:execute).with(1, 2).and_return(result)
|
21
24
|
stmt.execute(1, 2).should == result
|
22
25
|
end
|
26
|
+
|
27
|
+
context "with debug logging" do
|
28
|
+
before(:each) do
|
29
|
+
logger.level = Logger::DEBUG
|
30
|
+
executor.stub(:execute).and_return(result)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "logs the statement" do
|
34
|
+
logger.should_receive(:debug).with(/SELECT \* FROM bob WHERE \?.*?true/)
|
35
|
+
stmt.execute(true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "without debug logging" do
|
40
|
+
before(:each) do
|
41
|
+
logger.level = Logger::INFO
|
42
|
+
executor.stub(:execute).and_return(result)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does not log the statement" do
|
46
|
+
logger.should_not_receive(:debug)
|
47
|
+
stmt.execute(true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when an RDO::Exception occurs" do
|
52
|
+
before(:each) do
|
53
|
+
executor.stub(:execute).and_raise(RDO::Exception.new("some error"))
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with fatal logging" do
|
57
|
+
before(:each) do
|
58
|
+
logger.level = Logger::FATAL
|
59
|
+
end
|
60
|
+
|
61
|
+
it "logs the error" do
|
62
|
+
begin
|
63
|
+
logger.should_receive(:fatal).with(/some error/)
|
64
|
+
stmt.execute
|
65
|
+
fail("RDO::Exception should be raised")
|
66
|
+
rescue
|
67
|
+
# expected
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "without debug logging" do
|
73
|
+
before(:each) do
|
74
|
+
logger.level = Logger::UNKNOWN
|
75
|
+
end
|
76
|
+
|
77
|
+
it "does not log the error" do
|
78
|
+
begin
|
79
|
+
logger.should_not_receive(:fatal)
|
80
|
+
stmt.execute
|
81
|
+
fail("RDO::Exception should be raised")
|
82
|
+
rescue
|
83
|
+
# expected
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
23
88
|
end
|
24
89
|
end
|
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.1.0
|
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-
|
12
|
+
date: 2012-10-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- ext/rdo/extconf.rb
|
78
78
|
- ext/rdo/rdo.c
|
79
79
|
- lib/rdo.rb
|
80
|
+
- lib/rdo/colored_logger.rb
|
80
81
|
- lib/rdo/connection.rb
|
81
82
|
- lib/rdo/driver.rb
|
82
83
|
- lib/rdo/emulated_statement_executor.rb
|