rdo 0.0.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/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +309 -0
- data/Rakefile +2 -0
- data/lib/rdo.rb +32 -0
- data/lib/rdo/connection.rb +113 -0
- data/lib/rdo/driver.rb +120 -0
- data/lib/rdo/emulated_statement_executor.rb +36 -0
- data/lib/rdo/exception.rb +11 -0
- data/lib/rdo/result.rb +95 -0
- data/lib/rdo/statement.rb +28 -0
- data/lib/rdo/util.rb +102 -0
- data/lib/rdo/version.rb +3 -0
- data/rdo.gemspec +52 -0
- data/spec/rdo/connection_spec.rb +220 -0
- data/spec/rdo/driver_spec.rb +29 -0
- data/spec/rdo/emulated_statements_spec.rb +22 -0
- data/spec/rdo/result_spec.rb +117 -0
- data/spec/rdo/statement_spec.rb +24 -0
- data/spec/rdo/util_spec.rb +92 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/driver_with_everything.rb +38 -0
- data/spec/support/driver_without_statements.rb +23 -0
- data/util/macros.h +177 -0
- metadata +110 -0
@@ -0,0 +1,220 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RDO::Connection do
|
4
|
+
after(:each) { RDO::Connection.drivers.clear }
|
5
|
+
|
6
|
+
describe ".register_driver" do
|
7
|
+
before(:each) do
|
8
|
+
RDO::Connection.register_driver(:bob, RDO::Driver)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "registers a driver name for a driver class" do
|
12
|
+
RDO::Connection.drivers["bob"].should == RDO::Driver
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#initialize" do
|
17
|
+
let(:driver) { double(:driver, open: true) }
|
18
|
+
let(:driver_class) { double(new: driver) }
|
19
|
+
|
20
|
+
before(:each) { RDO::Connection.register_driver(:test, driver_class) }
|
21
|
+
|
22
|
+
context "with a connection uri string" do
|
23
|
+
context "for a registered driver" do
|
24
|
+
it "instantiates the driver" do
|
25
|
+
driver_class.should_receive(:new).and_return(driver)
|
26
|
+
RDO::Connection.new("test://whatever")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "converts the uri to an options hash" do
|
30
|
+
driver_class.should_receive(:new).
|
31
|
+
with(hash_including(driver: "test")).
|
32
|
+
and_return(driver)
|
33
|
+
|
34
|
+
RDO::Connection.new("test://whatever")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "parses the host name" do
|
38
|
+
driver_class.should_receive(:new).
|
39
|
+
with(hash_including(host: "whatever")).
|
40
|
+
and_return(driver)
|
41
|
+
|
42
|
+
RDO::Connection.new("test://whatever:3456")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "parses the username" do
|
46
|
+
driver_class.should_receive(:new).
|
47
|
+
with(hash_including(user: "bob")).
|
48
|
+
and_return(driver)
|
49
|
+
|
50
|
+
RDO::Connection.new("test://bob:@whatever:3456")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "parses the password" do
|
54
|
+
driver_class.should_receive(:new).
|
55
|
+
with(hash_including(password: "secret")).
|
56
|
+
and_return(driver)
|
57
|
+
|
58
|
+
RDO::Connection.new("test://user:secret@whatever:3456")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "parses the port number" do
|
62
|
+
driver_class.should_receive(:new).
|
63
|
+
with(hash_including(port: 3456)).
|
64
|
+
and_return(driver)
|
65
|
+
|
66
|
+
RDO::Connection.new("test://whatever:3456")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "parses the path" do
|
70
|
+
driver_class.should_receive(:new).
|
71
|
+
with(hash_including(path: "/some/path.db")).
|
72
|
+
and_return(driver)
|
73
|
+
|
74
|
+
RDO::Connection.new("test://whatever/some/path.db")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "parses the database name" do
|
78
|
+
driver_class.should_receive(:new).
|
79
|
+
with(hash_including(database: "my_db")).
|
80
|
+
and_return(driver)
|
81
|
+
|
82
|
+
RDO::Connection.new("test://whatever/my_db")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "parses the encoding" do
|
86
|
+
driver_class.should_receive(:new).
|
87
|
+
with(hash_including(encoding: "utf-8")).
|
88
|
+
and_return(driver)
|
89
|
+
|
90
|
+
RDO::Connection.new("test://whatever/my_db?encoding=utf-8")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "parses driver-specific options" do
|
94
|
+
driver_class.should_receive(:new).
|
95
|
+
with(hash_including(special_mode: "true")).
|
96
|
+
and_return(driver)
|
97
|
+
|
98
|
+
RDO::Connection.new("test://whatever/my_db?encoding=utf-8&special_mode=true")
|
99
|
+
end
|
100
|
+
|
101
|
+
context "with only a path" do
|
102
|
+
it "parses the path" do
|
103
|
+
driver_class.should_receive(:new).
|
104
|
+
with(hash_including(path: "/some/path.db")).
|
105
|
+
and_return(driver)
|
106
|
+
|
107
|
+
RDO::Connection.new("test:/some/path.db")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "invokes #open on the driver" do
|
112
|
+
driver.should_receive(:open).and_return(true)
|
113
|
+
RDO::Connection.new("test://host/db")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "for an unknown driver" do
|
118
|
+
it "raises an RDO::Exception" do
|
119
|
+
expect {
|
120
|
+
RDO::Connection.new("wat://ever")
|
121
|
+
}.to raise_error(RDO::Exception)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "with an options hash" do
|
127
|
+
context "for a registered driver" do
|
128
|
+
it "instantiates the driver" do
|
129
|
+
driver_class.should_receive(:new).and_return(driver)
|
130
|
+
RDO::Connection.new(driver: :test, host: "whatever")
|
131
|
+
end
|
132
|
+
|
133
|
+
it "passes the options to the driver" do
|
134
|
+
driver_class.should_receive(:new).
|
135
|
+
with(hash_including(host: "whatever")).
|
136
|
+
and_return(driver)
|
137
|
+
RDO::Connection.new(driver: :test, host: "whatever")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "invokes #open on the driver" do
|
141
|
+
driver.should_receive(:open).and_return(true)
|
142
|
+
RDO::Connection.new(driver: :test, host: "whatever")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "for an unknown driver" do
|
147
|
+
it "raises an RDO::Exception" do
|
148
|
+
expect {
|
149
|
+
RDO::Connection.new(driver: :wat, host: "test")
|
150
|
+
}.to raise_error(RDO::Exception)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "driver methods" do
|
157
|
+
let(:connection) { RDO::Connection.new("test://host") }
|
158
|
+
let(:driver) { double(:driver, open: true) }
|
159
|
+
let(:driver_class) { double(new: driver) }
|
160
|
+
|
161
|
+
before(:each) do
|
162
|
+
RDO::Connection.register_driver(:test, driver_class)
|
163
|
+
connection
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#open" do
|
167
|
+
it "delegates to the driver" do
|
168
|
+
driver.should_receive(:open).and_return(true)
|
169
|
+
connection.open.should == true
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#close" do
|
174
|
+
it "delegates to the driver" do
|
175
|
+
driver.should_receive(:close).and_return(true)
|
176
|
+
connection.close.should == true
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "#open?" do
|
181
|
+
it "delegates to the driver" do
|
182
|
+
driver.should_receive(:open?).and_return(false)
|
183
|
+
connection.should_not be_open
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe "#execute" do
|
188
|
+
let(:result) { RDO::Result.new([]) }
|
189
|
+
|
190
|
+
it "delegates to the driver" do
|
191
|
+
driver.should_receive(:execute).
|
192
|
+
with("SELECT * FROM bob WHERE ?", true).
|
193
|
+
and_return(result)
|
194
|
+
connection.execute("SELECT * FROM bob WHERE ?", true).should == result
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "#prepare" do
|
199
|
+
let(:stmt) { RDO::Statement.new(stub(:executor)) }
|
200
|
+
|
201
|
+
it "delegates to the driver" do
|
202
|
+
driver.should_receive(:prepare).
|
203
|
+
with("SELECT * FROM bob WHERE ?").
|
204
|
+
and_return(stmt)
|
205
|
+
connection.prepare("SELECT * FROM bob WHERE ?").should == stmt
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "#quote" do
|
210
|
+
let(:quoted) { "Weird ['] quotes" }
|
211
|
+
|
212
|
+
it "delegates to the driver" do
|
213
|
+
driver.should_receive(:quote).
|
214
|
+
with("Weird ' quotes").
|
215
|
+
and_return(quoted)
|
216
|
+
connection.quote("Weird ' quotes").should == quoted
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RDO::Driver do
|
4
|
+
describe "#initialize" do
|
5
|
+
it "does not call #open" do
|
6
|
+
RDO::DriverWithEverything.new.should_not be_open
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#prepare" do
|
11
|
+
let(:driver) { RDO::DriverWithoutStatements.new }
|
12
|
+
|
13
|
+
it "returns a Statement" do
|
14
|
+
driver.prepare("SELECT * FROM bob WHERE ?").should be_a_kind_of(RDO::Statement)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has the correct command" do
|
18
|
+
driver.prepare("SELECT * FROM bob WHERE ?").command.should == "SELECT * FROM bob WHERE ?"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "calls #execute on the driver" do
|
22
|
+
driver.should_receive(:execute).
|
23
|
+
with("SELECT * FROM bob WHERE ?", true).
|
24
|
+
and_return(RDO::Result.new([]))
|
25
|
+
stmt = driver.prepare("SELECT * FROM bob WHERE ?")
|
26
|
+
stmt.execute(true).should be_a_kind_of(RDO::Result)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RDO::Driver, "emulated prepared statements" do
|
4
|
+
let(:driver) { RDO::DriverWithoutStatements.new }
|
5
|
+
|
6
|
+
describe "#command" do
|
7
|
+
it "returns the command string" do
|
8
|
+
driver.prepare("SELECT * FROM users").command.should == "SELECT * FROM users"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#execute" do
|
13
|
+
let(:result) { stub(:result) }
|
14
|
+
|
15
|
+
it "delegates to the driver" do
|
16
|
+
driver.should_receive(:execute).with(
|
17
|
+
"SELECT * FROM users WHERE ? AND ?", 1, 2
|
18
|
+
).and_return(result)
|
19
|
+
driver.prepare("SELECT * FROM users WHERE ? AND ?").execute(1, 2).should == result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RDO::Result do
|
4
|
+
it "is enumerable" do
|
5
|
+
RDO::Result.new([]).should be_a_kind_of(Enumerable)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#each" do
|
9
|
+
let(:result) { RDO::Result.new([{id: 7}, {id: 42}]) }
|
10
|
+
|
11
|
+
it "enumerates all tuples" do
|
12
|
+
tuples = []
|
13
|
+
result.each{|row| tuples << row}
|
14
|
+
tuples.should == [{id: 7}, {id: 42}]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns the result" do
|
18
|
+
result.each.should equal(result)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#info" do
|
23
|
+
let(:result) { RDO::Result.new([], foo: "bar", zip: 42) }
|
24
|
+
|
25
|
+
it "returns all info passed to #initialize" do
|
26
|
+
result.info.should == {foo: "bar", zip: 42}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#insert_id" do
|
31
|
+
context "when provided in the info" do
|
32
|
+
let(:result) { RDO::Result.new([], insert_id: 21) }
|
33
|
+
|
34
|
+
it "returns the ID from the info" do
|
35
|
+
result.insert_id.should == 21
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when not provided in the info" do
|
40
|
+
context "and there are tuples" do
|
41
|
+
let(:result) { RDO::Result.new([{id: 6, name: "bob"}]) }
|
42
|
+
|
43
|
+
it "infers from the tuples" do
|
44
|
+
result.insert_id.should == 6
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "and there are no tuples" do
|
49
|
+
let(:result) { RDO::Result.new([]) }
|
50
|
+
|
51
|
+
it "returns nil" do
|
52
|
+
result.insert_id.should be_nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#affected_rows" do
|
59
|
+
context "when provided in the info" do
|
60
|
+
let(:result) { RDO::Result.new([], affected_rows: 3) }
|
61
|
+
|
62
|
+
it "returns the value from the info" do
|
63
|
+
result.affected_rows.should == 3
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when not provided in the info" do
|
68
|
+
let(:result) { RDO::Result.new([]) }
|
69
|
+
|
70
|
+
it "returns nil" do
|
71
|
+
result.insert_id.should be_nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#count" do
|
77
|
+
context "when provided in the info" do
|
78
|
+
let(:result) { RDO::Result.new([{id: 7}, {id: 42}], count: 50) }
|
79
|
+
|
80
|
+
it "returns the count from the info" do
|
81
|
+
result.count.should == 50
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with a block given" do
|
85
|
+
it "delegates to Enumerable" do
|
86
|
+
result.count{|row| row[:id] > 10}.should == 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when not provided in the info" do
|
92
|
+
let(:result) { RDO::Result.new([{id: 7}, {id: 42}]) }
|
93
|
+
|
94
|
+
it "delegates to Enumerable" do
|
95
|
+
result.count.should == 2
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#first_value" do
|
101
|
+
context "when there are tuples" do
|
102
|
+
let(:result) { RDO::Result.new([{id: 6, name: "bob"}]) }
|
103
|
+
|
104
|
+
it "reads the first column in the first tuple" do
|
105
|
+
result.first_value.should == 6
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when there are no tuples" do
|
110
|
+
let(:result) { RDO::Result.new([]) }
|
111
|
+
|
112
|
+
it "returns nil" do
|
113
|
+
result.first_value.should be_nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RDO::Statement do
|
4
|
+
let(:executor) { double(:executor) }
|
5
|
+
let(:stmt) { RDO::Statement.new(executor) }
|
6
|
+
|
7
|
+
describe "#command" do
|
8
|
+
let(:command) { "SELECT * FROM users" }
|
9
|
+
|
10
|
+
it "delegates to the executor" do
|
11
|
+
executor.should_receive(:command).and_return(command)
|
12
|
+
stmt.command.should == command
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#execute" do
|
17
|
+
let(:result) { stub(:result) }
|
18
|
+
|
19
|
+
it "delegates to the executor" do
|
20
|
+
executor.should_receive(:execute).with(1, 2).and_return(result)
|
21
|
+
stmt.execute(1, 2).should == result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RDO::Util do
|
4
|
+
describe ".system_time_zone" do
|
5
|
+
it "returns the time zone of the local system" do
|
6
|
+
require "date"
|
7
|
+
RDO::Util.system_time_zone.should == DateTime.now.zone
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".float" do
|
12
|
+
context "with Infinity" do
|
13
|
+
it "returns Float::INFINITY" do
|
14
|
+
RDO::Util.float("Infinity").should == Float::INFINITY
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "with -Infinity" do
|
19
|
+
it "returns -Float::INFINITY" do
|
20
|
+
RDO::Util.float("-Infinity").should == -Float::INFINITY
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with NaN" do
|
25
|
+
it "returns Float::NAN" do
|
26
|
+
RDO::Util.float("NaN").should be_nan
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with a number" do
|
31
|
+
it "returns a Float" do
|
32
|
+
RDO::Util.float("1.2").should == 1.2
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with an exponent" do
|
37
|
+
it "returns a Float" do
|
38
|
+
RDO::Util.float("1.1E-2").should == Float("1.1E-2")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "decimal" do
|
44
|
+
context "with NaN" do
|
45
|
+
it "returns NaN" do
|
46
|
+
RDO::Util.decimal("NaN").should be_nan
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with a number" do
|
51
|
+
it "returns a BigDecimal" do
|
52
|
+
require "bigdecimal"
|
53
|
+
RDO::Util.decimal("1.2").should == BigDecimal("1.2")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with an exponent" do
|
58
|
+
it "returns a BigDecimal" do
|
59
|
+
require "bigdecimal"
|
60
|
+
RDO::Util.decimal("1E-2").should == BigDecimal("1E-2")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe ".date" do
|
66
|
+
it "returns a Date" do
|
67
|
+
RDO::Util.date("2012-09-22").should == Date.new(2012, 9, 22)
|
68
|
+
end
|
69
|
+
|
70
|
+
context "with BC" do
|
71
|
+
it "returns a Date" do
|
72
|
+
RDO::Util.date("431-09-22 BC").should == Date.new(-430, 9, 22)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe ".date_time_with_zone" do
|
78
|
+
it "returns a DateTime" do
|
79
|
+
require "date"
|
80
|
+
RDO::Util.date_time_with_zone("2012-09-22 10:04:32 +06:00").should ==
|
81
|
+
DateTime.parse("2012-09-22 10:04:32 +06:00")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe ".date_time_without_zone" do
|
86
|
+
it "returns a DateTime in the system time zone" do
|
87
|
+
require "date"
|
88
|
+
RDO::Util.date_time_without_zone("2012-09-22 10:04:32").should ==
|
89
|
+
DateTime.parse("2012-09-22 10:04:32 #{DateTime.now.zone}")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|