rdo 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,5 +3,6 @@ script: "bundle exec rake spec"
3
3
  rvm:
4
4
  - 1.9.2
5
5
  - 1.9.3
6
+ - rbx-19mode
6
7
  notifications:
7
8
  email: chris@w3style.co.uk
data/README.md CHANGED
@@ -1,15 +1,17 @@
1
- # RDO—Ruby Data Objects
1
+ # RDO—Database Connectivity for Ruby
2
2
 
3
3
  RDO provides a simple, robust standardized way to access various RDBMS
4
4
  implementations in Ruby. Drivers all conform to the same, beautiful rubyesque
5
- interface. Where a feature is not natively supported by the DBMS—for example,
5
+ interface. Where a feature is not natively supported by the DBMS—perhaps
6
6
  prepared statements—it is seamlessly emulated, so you don't need to code
7
7
  around it.
8
8
 
9
- It targets **Ruby 1.9** and newer.
9
+ It targets **Ruby 1.9** and newer (including Rubinius 2.0).
10
10
 
11
11
  [![Build Status](https://secure.travis-ci.org/d11wtq/rdo.png?branch=master)](http://travis-ci.org/d11wtq/rdo)
12
12
 
13
+ **RDO** stands for Ruby Data Objects.
14
+
13
15
  ``` ruby
14
16
  require "rdo"
15
17
  require "rdo-postgres"
@@ -36,27 +38,7 @@ end
36
38
  conn.close
37
39
  ```
38
40
 
39
- ## Strange looking ORM you have there, Sir
40
-
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
-
47
- Or perhaps you're actually writing the next kick-ass ORM? Either way, RDO
48
- just lets you talk directly to your database.
49
-
50
- ## What's the point?
51
-
52
- Let's face it, we've been writing database applications since the dark ages—
53
- it's not that hard. What's lacking from Ruby, however, is any consistency for
54
- dealing with a database directly. Several beautiful ORMs exist, but they
55
- serve a different need. [DataMapper](https://github.com/datamapper/dm-core)
56
- has a layer underneath it called [data_objects](https://github.com/datamapper/do),
57
- but it isn't particularly user-friendly when used standalone and it requires
58
- jumping through hoops to deal with certain database RDBMS features, such as
59
- PostgreSQL bytea fields (which, in RDO, "just work").
41
+ ## Features
60
42
 
61
43
  RDO makes the following things standard:
62
44
 
@@ -65,10 +47,11 @@ RDO makes the following things standard:
65
47
  - **Prepared statements** where possible; emulated where not
66
48
  - **Type-casting** to equivalent Ruby types (e.g. Fixnum, BigDecimal,
67
49
  Float, even Array)
68
- - Access meta data after write operations, with insert IDs standardized
50
+ - Access result information after write operations, with insert IDs standardized
69
51
  - **Use simple core data types** (Hash) for reading values and field names
70
52
 
71
53
  Note that data-type support is limited to whatever the DBMS actually supports.
54
+ See individual driver READMEs for type support information.
72
55
 
73
56
  ## Installation
74
57
 
@@ -133,6 +116,9 @@ And then execute:
133
116
  </tbody>
134
117
  </table>
135
118
 
119
+ I'm looking for contributors to develop and maintain drivers for other vendors:
120
+ Oracle, SQL Server and DB2 are of interest. Your project would be linked above.
121
+
136
122
  ## Usage
137
123
 
138
124
  The interface for RDO is intentionally minimal. It should take a few minutes
@@ -179,9 +165,9 @@ p conn.open? #=> true
179
165
 
180
166
  ### Performing non-read commands
181
167
 
182
- All SQL and DDL (Data Definition Language) is executed with #execute, which
183
- always returns a RDO::Result object. Query inputs should be provided as
184
- binding placeholders and additional arguments. No explicit type-conversion is
168
+ Any command supported by the DBMS is executed with #execute, which always
169
+ returns a RDO::Result object. Query inputs should be provided as binding
170
+ placeholders and additional arguments. No explicit type-conversion is
185
171
  necessary.
186
172
 
187
173
  ``` ruby
@@ -211,8 +197,8 @@ include any error messaage provided by the DBMS.
211
197
  ### Performing read queries
212
198
 
213
199
  There is no difference in the interface for reads or writes. Just call
214
- the #execute method in both cases. This always returns a RDO::Result.
215
- RDO::Result includes the Enumerable module. Some operations, such as #count
200
+ the #execute method in both cases. This always returns an RDO::Result,
201
+ which includes the Enumerable module. Some operations, such as #count
216
202
  may be optimized by the driver.
217
203
 
218
204
  ``` ruby
@@ -270,16 +256,14 @@ conn.execute("INSERT INTO users (name) VALUES ('#{conn.quote(params[:name])}')")
270
256
  RDO uses Symbols as keys in the hashes that represent data rows. Most of the
271
257
  time this is desirable. If you query for something that returns field names
272
258
  containing spaces, or punctuation, you need to convert a String to a Symbol
273
- using #to_sym or #intern. Or wrap the Hash with a Mash of some sort.
259
+ using #to_sym or #intern. Or use a quoted Symbol-literal.
274
260
 
275
261
  ``` ruby
276
262
  result = conn(%q{SELECT 42 AS "The Meaning"})
263
+ p result.first[:"The Meaning"]
277
264
  p result.first["The Meaning".intern]
278
265
  ```
279
266
 
280
- I weighed up the possibility of using a custom data type, but I prefer core
281
- ruby types unless there's an overwhelming reason to use a custom type, sorry.
282
-
283
267
  ### Selecting just a single value
284
268
 
285
269
  RDO::Result has a #first_value method for convenience if you are only
@@ -303,6 +287,13 @@ DEBUG severity. Errors will be logged with FATAL severity.
303
287
  RDO.connect("postgres://user:pass@host/db", logger: Logger.new(STDOUT))
304
288
  ```
305
289
 
290
+ You can access the logger through `connection.logger`.
291
+
292
+ ``` ruby
293
+ conn.logger.level = Logger::DEBUG
294
+ conn.logger.debug? #=> true
295
+ ```
296
+
306
297
  A logger with some support for highlighting errors etc and which shows
307
298
  query execution times is configured (but disabled) by default. It is
308
299
  found at `RDO::ColoredLogger`. You can enable it by specify a log level:
@@ -320,7 +311,7 @@ Turning on debug logging globally is often a little overkill and too noisy.
320
311
  You may enable debug logging in the context of a block, like so:
321
312
 
322
313
  ``` ruby
323
- connection.debug do
314
+ conn.debug do
324
315
  # call some methods that execute SQL
325
316
  end
326
317
  ```
@@ -335,8 +326,7 @@ Your contribution will be recognized here. If you don't know how to fix it,
335
326
  file an issue in the issue tracker on GitHub.
336
327
 
337
328
  When sending pull requests, please use topic branches—don't send a pull
338
- request from the master branch of your fork, as that may change
339
- unintentionally.
329
+ request from the master branch of your fork.
340
330
 
341
331
  I haven't looked at what I need to change to have the drivers compile on
342
332
  Windows yet, but I will do. If anybody beats me to it, pull requests will
@@ -349,22 +339,39 @@ parts of the Ruby API I use are very typical.
349
339
 
350
340
  The more drivers that RDO has support for, the better. Writing drivers for
351
341
  RDO is quite painless. They are just thin wrappers around the C API for the
352
- DBMS, which conform to RDO's interface.
342
+ DBMS, which conform to RDO's Driver interface.
343
+
344
+ ```
345
+ RDO::Driver
346
+ - open
347
+ - open?
348
+ - close
349
+ - execute
350
+ - prepare
351
+ - quote
352
+ ```
353
+
354
+ The #execute method returns an RDO::Result, which takes any Enumerable and
355
+ some options in its initializer. The Enumerable just iterates over the rows
356
+ in the result. The options Hash provides result information.
357
+
358
+ The #prepare method is optional, but should return an Object with the
359
+ following methods:
360
+
361
+ ```
362
+ RDO::StatementExecutor
363
+ - command
364
+ - execute
365
+ ```
366
+
367
+ The #command method just provides the String form of the statement. The #execute
368
+ method returns an RDO::Result, as per the Driver.
353
369
 
354
370
  Some of the more boilerplate things you'd normally have to do are covered by
355
371
  C macros in the util/macros.h file you'll find in this repository. Copy that
356
372
  file to your own project and include it for one-line type conversions etc.
357
373
  Take a look at one of the existing drivers to get an idea how to write a
358
- driver.
359
-
360
- Because one person could not possibly maintain drivers for all conceivable
361
- DBMS's, it is better that different developers write and maintain different
362
- drivers. If you have written a driver for RDO, please fork this git repo and
363
- edit this README to list it, then send a pull request. That way others will
364
- find it more easily.
365
-
366
- I'm particularly interested in drivers for Oracle and Microsoft SQL Server,
367
- though I don't personally use these.
374
+ driver (rdo-sqlite and rdo-mysql are probably simple ones).
368
375
 
369
376
  ## Copyright & Licensing
370
377
 
@@ -81,10 +81,18 @@ module RDO
81
81
  if info[:count].nil? || block_given?
82
82
  super
83
83
  else
84
- info[:count]
84
+ info[:count].to_i
85
85
  end
86
86
  end
87
87
 
88
+ # Check if the result has no rows.
89
+ #
90
+ # @return [Boolean]
91
+ # true if the result has no returned rows
92
+ def empty?
93
+ count.zero?
94
+ end
95
+
88
96
  # Get the time spent processing the statement.
89
97
  #
90
98
  # @return [Float]
@@ -6,5 +6,5 @@
6
6
  ##
7
7
 
8
8
  module RDO
9
- VERSION = "0.1.6"
9
+ VERSION = "0.1.7"
10
10
  end
@@ -97,6 +97,24 @@ describe RDO::Result do
97
97
  end
98
98
  end
99
99
 
100
+ describe "#empty?" do
101
+ context "when #count == 0" do
102
+ let(:result) { RDO::Result.new([], count: 0) }
103
+
104
+ it "returns true" do
105
+ result.should be_empty
106
+ end
107
+ end
108
+
109
+ context "when #count > 0" do
110
+ let(:result) { RDO::Result.new([], count: 1) }
111
+
112
+ it "returns false" do
113
+ result.should_not be_empty
114
+ end
115
+ end
116
+ end
117
+
100
118
  describe "#first_value" do
101
119
  context "when there are tuples" do
102
120
  let(:result) { RDO::Result.new([{id: 6, name: "bob"}]) }
@@ -37,6 +37,25 @@
37
37
  */
38
38
  #define RDO_ERROR(...) (rb_raise(rb_path2class("RDO::Exception"), __VA_ARGS__))
39
39
 
40
+ /**
41
+ * Calls Driver#interpolate for args.
42
+ *
43
+ * @param VALUE (RDO::Driver)
44
+ * the Driver to use #quote from
45
+ *
46
+ * @param (VALUE *) args
47
+ * a C array where the first element is the SQL and the remainder are the bind params
48
+ *
49
+ * @param int argc
50
+ * the number of elements in args
51
+ *
52
+ * @return VALUE (String)
53
+ * a Ruby String with the SQL including the interpolated params
54
+ */
55
+ #define RDO_INTERPOLATE(driver, args, argc) \
56
+ (rb_funcall(driver, rb_intern("interpolate"), 2, \
57
+ args[0], rb_ary_new4(argc - 1, &args[1])))
58
+
40
59
  /**
41
60
  * Factory to return a new RDO::Result for an Enumerable object of tuples.
42
61
  *
@@ -52,18 +71,6 @@
52
71
  #define RDO_RESULT(tuples, info) \
53
72
  (rb_funcall(rb_path2class("RDO::Result"), rb_intern("new"), 2, tuples, info))
54
73
 
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
-
67
74
  /**
68
75
  * Convert a C string to a ruby String.
69
76
  *
@@ -77,7 +84,8 @@
77
84
  * a Ruby String
78
85
  */
79
86
  #define RDO_STRING(s, len, enc) \
80
- (rb_enc_associate_index(rb_str_new(s, len), enc > 0 ? enc : 0))
87
+ (rb_enc_associate_index(rb_str_new(s, len), \
88
+ enc > 0 ? enc : rb_enc_find_index("binary")))
81
89
 
82
90
  /**
83
91
  * Convert a C string to a ruby String, assuming possible NULL bytes.
@@ -91,7 +99,8 @@
91
99
  * @return VALUE (String)
92
100
  * a Ruby String
93
101
  */
94
- #define RDO_BINARY_STRING(s, len) (rb_str_new(s, len))
102
+ #define RDO_BINARY_STRING(s, len) \
103
+ (RDO_STRING(s, len, rb_enc_find_index("binary")))
95
104
 
96
105
  /**
97
106
  * Convert a C string to a Fixnum.
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.1.6
4
+ version: 0.1.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-10-14 00:00:00.000000000 Z
12
+ date: 2012-10-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec