data_objects 0.9.11 → 0.9.12
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/Manifest.txt +19 -1
- data/Rakefile +6 -80
- data/lib/data_objects.rb +1 -6
- data/lib/data_objects/command.rb +51 -1
- data/lib/data_objects/connection.rb +13 -2
- data/lib/data_objects/logger.rb +40 -32
- data/lib/data_objects/quoting.rb +28 -32
- data/lib/data_objects/reader.rb +6 -5
- data/lib/data_objects/result.rb +7 -1
- data/lib/data_objects/spec/command_spec.rb +191 -0
- data/lib/data_objects/spec/connection_spec.rb +106 -0
- data/lib/data_objects/spec/encoding_spec.rb +31 -0
- data/lib/data_objects/spec/quoting_spec.rb +0 -0
- data/lib/data_objects/spec/reader_spec.rb +156 -0
- data/lib/data_objects/spec/result_spec.rb +58 -0
- data/lib/data_objects/spec/typecast/array_spec.rb +36 -0
- data/lib/data_objects/spec/typecast/bigdecimal_spec.rb +107 -0
- data/lib/data_objects/spec/typecast/boolean_spec.rb +107 -0
- data/lib/data_objects/spec/typecast/byte_array_spec.rb +86 -0
- data/lib/data_objects/spec/typecast/class_spec.rb +63 -0
- data/lib/data_objects/spec/typecast/date_spec.rb +108 -0
- data/lib/data_objects/spec/typecast/datetime_spec.rb +110 -0
- data/lib/data_objects/spec/typecast/float_spec.rb +111 -0
- data/lib/data_objects/spec/typecast/integer_spec.rb +86 -0
- data/lib/data_objects/spec/typecast/ipaddr_spec.rb +0 -0
- data/lib/data_objects/spec/typecast/nil_spec.rb +116 -0
- data/lib/data_objects/spec/typecast/range_spec.rb +36 -0
- data/lib/data_objects/spec/typecast/string_spec.rb +86 -0
- data/lib/data_objects/spec/typecast/time_spec.rb +64 -0
- data/lib/data_objects/transaction.rb +20 -13
- data/lib/data_objects/uri.rb +24 -2
- data/lib/data_objects/version.rb +2 -1
- data/spec/command_spec.rb +1 -17
- data/spec/connection_spec.rb +1 -23
- data/spec/lib/pending_helpers.rb +11 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/result_spec.rb +0 -3
- data/tasks/gem.rake +49 -0
- data/tasks/install.rake +13 -0
- data/tasks/release.rake +74 -0
- data/tasks/spec.rake +18 -0
- metadata +51 -30
- data/.gitignore +0 -2
- data/spec/dataobjects_spec.rb +0 -1
- data/spec/spec.opts +0 -2
@@ -0,0 +1,36 @@
|
|
1
|
+
share_examples_for 'supporting Range' do
|
2
|
+
|
3
|
+
include DataObjectsSpecHelpers
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
setup_test_environment
|
7
|
+
end
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
@connection = DataObjects::Connection.new(CONFIG.uri)
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
@connection.close
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'passing a Range as a parameter in execute_reader' do
|
18
|
+
|
19
|
+
before do
|
20
|
+
@reader = @connection.create_command("SELECT * FROM widgets WHERE id between ?").execute_reader(2..5)
|
21
|
+
end
|
22
|
+
|
23
|
+
after do
|
24
|
+
@reader.close
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return correct number of rows' do
|
28
|
+
counter = 0
|
29
|
+
while(@reader.next!) do
|
30
|
+
counter += 1
|
31
|
+
end
|
32
|
+
counter.should == 4
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
share_examples_for 'supporting String' do
|
2
|
+
|
3
|
+
include DataObjectsSpecHelpers
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
setup_test_environment
|
7
|
+
end
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
@connection = DataObjects::Connection.new(CONFIG.uri)
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
@connection.close
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'reading a String' do
|
18
|
+
|
19
|
+
describe 'with automatic typecasting' do
|
20
|
+
|
21
|
+
before do
|
22
|
+
@reader = @connection.create_command("SELECT code FROM widgets WHERE ad_description = ?").execute_reader('Buy this product now!')
|
23
|
+
@reader.next!
|
24
|
+
@values = @reader.values
|
25
|
+
end
|
26
|
+
|
27
|
+
after do
|
28
|
+
@reader.close
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should return the correctly typed result' do
|
32
|
+
@values.first.should be_kind_of(String)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should return the correct result' do
|
36
|
+
@values.first.should == "W0000001"
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'with manual typecasting' do
|
42
|
+
|
43
|
+
before do
|
44
|
+
@command = @connection.create_command("SELECT weight FROM widgets WHERE ad_description = ?")
|
45
|
+
@command.set_types(String)
|
46
|
+
@reader = @command.execute_reader('Buy this product now!')
|
47
|
+
@reader.next!
|
48
|
+
@values = @reader.values
|
49
|
+
end
|
50
|
+
|
51
|
+
after do
|
52
|
+
@reader.close
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should return the correctly typed result' do
|
56
|
+
@values.first.should be_kind_of(String)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return the correct result' do
|
60
|
+
@values.first.should == "13.4"
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'writing a String' do
|
68
|
+
|
69
|
+
before do
|
70
|
+
@reader = @connection.create_command("SELECT id FROM widgets WHERE id = ?").execute_reader("2")
|
71
|
+
@reader.next!
|
72
|
+
@values = @reader.values
|
73
|
+
end
|
74
|
+
|
75
|
+
after do
|
76
|
+
@reader.close
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should return the correct entry' do
|
80
|
+
# Some of the drivers starts autoincrementation from 0 not 1
|
81
|
+
@values.first.should satisfy { |val| val == 1 or val == 2 }
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
share_examples_for 'supporting Time' do
|
2
|
+
|
3
|
+
include DataObjectsSpecHelpers
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
setup_test_environment
|
7
|
+
end
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
@connection = DataObjects::Connection.new(CONFIG.uri)
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
@connection.close
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'reading a Time' do
|
18
|
+
|
19
|
+
describe 'with manual typecasting' do
|
20
|
+
|
21
|
+
before do
|
22
|
+
@command = @connection.create_command("SELECT release_date FROM widgets WHERE ad_description = ?")
|
23
|
+
@command.set_types(Time)
|
24
|
+
@reader = @command.execute_reader('Buy this product now!')
|
25
|
+
@reader.next!
|
26
|
+
@values = @reader.values
|
27
|
+
end
|
28
|
+
|
29
|
+
after do
|
30
|
+
@reader.close
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should return the correctly typed result' do
|
34
|
+
@values.first.should be_kind_of(Time)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return the correct result' do
|
38
|
+
@values.first.should == Time.local(2008, 2, 14)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'writing an Time' do
|
46
|
+
|
47
|
+
before do
|
48
|
+
@reader = @connection.create_command("SELECT id FROM widgets WHERE release_datetime = ?").execute_reader(Time.utc(2008, 2, 14, 00, 31, 12))
|
49
|
+
@reader.next!
|
50
|
+
@values = @reader.values
|
51
|
+
end
|
52
|
+
|
53
|
+
after do
|
54
|
+
@reader.close
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should return the correct entry' do
|
58
|
+
#Some of the drivers starts autoincrementation from 0 not 1
|
59
|
+
@values.first.should satisfy { |val| val == 1 or val == 0 }
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -5,41 +5,48 @@ module DataObjects
|
|
5
5
|
|
6
6
|
class Transaction
|
7
7
|
|
8
|
+
# The host name. Note, this relies on the host name being configured and resolvable using DNS
|
8
9
|
HOST = "#{Socket::gethostbyname(Socket::gethostname)[0]}" rescue "localhost"
|
9
10
|
@@counter = 0
|
10
11
|
|
12
|
+
# The connection object allocated for this transaction
|
11
13
|
attr_reader :connection
|
14
|
+
# A unique ID for this transaction
|
12
15
|
attr_reader :id
|
13
16
|
|
17
|
+
# Instantiate the Transaction subclass that's appropriate for this uri scheme
|
14
18
|
def self.create_for_uri(uri)
|
15
19
|
uri = uri.is_a?(String) ? URI::parse(uri) : uri
|
16
20
|
DataObjects.const_get(uri.scheme.capitalize)::Transaction.new(uri)
|
17
21
|
end
|
18
22
|
|
19
23
|
#
|
20
|
-
# Creates a Transaction bound to the given
|
21
|
-
#
|
22
|
-
# ==== Parameters
|
23
|
-
# conn<DataObjects::Connection>:: The Connection to bind the new Transaction to
|
24
|
+
# Creates a Transaction bound to a connection for the given DataObjects::URI
|
24
25
|
#
|
25
26
|
def initialize(uri)
|
26
27
|
@connection = DataObjects::Connection.new(uri)
|
27
28
|
@id = Digest::SHA256.hexdigest("#{HOST}:#{$$}:#{Time.now.to_f}:#{@@counter += 1}")
|
28
29
|
end
|
29
30
|
|
31
|
+
# Close the connection for this Transaction
|
30
32
|
def close
|
31
33
|
@connection.close
|
32
34
|
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
|
36
|
+
# Begin the Transaction
|
37
|
+
def begin; not_implemented; end
|
38
|
+
# Commit changes made in this Transaction
|
39
|
+
def commit; not_implemented; end
|
40
|
+
# Rollback changes made in this Transaction
|
41
|
+
def rollback; not_implemented; end;
|
42
|
+
# Prepare this Transaction for the second phase of a two-phase commit
|
43
|
+
def prepare; not_implemented; end;
|
44
|
+
# Abandon the second phase of a two-phase commit and roll back the changes
|
45
|
+
def rollback_prepared; not_implemented; end;
|
46
|
+
|
47
|
+
private
|
48
|
+
def not_implemented
|
49
|
+
raise NotImplementedError
|
42
50
|
end
|
43
|
-
|
44
51
|
end
|
45
52
|
end
|
data/lib/data_objects/uri.rb
CHANGED
@@ -2,15 +2,27 @@ gem 'addressable', '~>2.0'
|
|
2
2
|
require 'addressable/uri'
|
3
3
|
|
4
4
|
module DataObjects
|
5
|
-
URI = Struct.new(:scheme, :user, :password, :host, :port, :path, :query, :fragment)
|
6
5
|
|
7
|
-
|
6
|
+
# A DataObjects URI is of the form scheme://user:password@host:port/path#fragment
|
7
|
+
#
|
8
|
+
# The elements are all optional except scheme and path:
|
9
|
+
# scheme:: The name of a DBMS for which you have a do_\<scheme\> adapter gem installed. If scheme is *jdbc*, the actual DBMS is in the _path_ followed by a colon.
|
10
|
+
# user:: The name of the user to authenticate to the database
|
11
|
+
# password:: The password to use in authentication
|
12
|
+
# host:: The domain name (defaulting to localhost) where the database is available
|
13
|
+
# port:: The TCP/IP port number to use for the connection
|
14
|
+
# path:: The name or path to the database
|
15
|
+
# query:: Parameters for the connection, for example encoding=utf8
|
16
|
+
# fragment:: Not currently known to be in use, but available to the adapters
|
17
|
+
class URI < Struct.new(:scheme, :user, :password, :host, :port, :path, :query, :fragment)
|
18
|
+
# Make a DataObjects::URI object by parsing a string. Simply delegates to Addressable::URI::parse.
|
8
19
|
def self.parse(uri)
|
9
20
|
return uri if uri.kind_of?(self)
|
10
21
|
uri = Addressable::URI::parse(uri) unless uri.kind_of?(Addressable::URI)
|
11
22
|
self.new(uri.scheme, uri.user, uri.password, uri.host, uri.port, uri.path, uri.query_values, uri.fragment)
|
12
23
|
end
|
13
24
|
|
25
|
+
# Display this URI object as a string
|
14
26
|
def to_s
|
15
27
|
string = ""
|
16
28
|
string << "#{scheme}://" if scheme
|
@@ -30,5 +42,15 @@ module DataObjects
|
|
30
42
|
string << "##{fragment}" if fragment
|
31
43
|
string
|
32
44
|
end
|
45
|
+
|
46
|
+
# Compare this URI to another for hashing
|
47
|
+
def eql?(other)
|
48
|
+
to_s.eql?(other.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Hash this URI
|
52
|
+
def hash
|
53
|
+
to_s.hash
|
54
|
+
end
|
33
55
|
end
|
34
56
|
end
|
data/lib/data_objects/version.rb
CHANGED
data/spec/command_spec.rb
CHANGED
@@ -10,15 +10,7 @@ describe DataObjects::Command do
|
|
10
10
|
@connection.close
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
@command.instance_variable_get("@connection").should == @connection
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should assign the sql text to @text" do
|
18
|
-
@command.instance_variable_get("@text").should == 'SQL STRING'
|
19
|
-
end
|
20
|
-
|
21
|
-
%w{connection execute_non_query execute_reader set_types to_s}.each do |meth|
|
13
|
+
%w{connection execute_non_query execute_reader set_types}.each do |meth|
|
22
14
|
it "should respond to ##{meth}" do
|
23
15
|
@command.should respond_to(meth.intern)
|
24
16
|
end
|
@@ -30,12 +22,4 @@ describe DataObjects::Command do
|
|
30
22
|
end
|
31
23
|
end
|
32
24
|
|
33
|
-
it "should make the connection object available in #connection" do
|
34
|
-
@command.connection.should == @command.instance_variable_get("@connection")
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should make the SQL text available in #to_s" do
|
38
|
-
@command.to_s.should == @command.instance_variable_get("@text")
|
39
|
-
end
|
40
|
-
|
41
25
|
end
|
data/spec/connection_spec.rb
CHANGED
@@ -20,15 +20,6 @@ describe DataObjects::Connection do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
describe "initialization" do
|
23
|
-
it "should accept a regular connection uri as a String" do
|
24
|
-
c = DataObjects::Connection.new('mock://localhost/database')
|
25
|
-
# relying on the fact that mock connection sets @uri
|
26
|
-
uri = c.instance_variable_get("@uri")
|
27
|
-
|
28
|
-
uri.scheme.should == 'mock'
|
29
|
-
uri.host.should == 'localhost'
|
30
|
-
uri.path.should == '/database'
|
31
|
-
end
|
32
23
|
|
33
24
|
it "should accept a connection uri as a Addressable::URI" do
|
34
25
|
c = DataObjects::Connection.new(Addressable::URI::parse('mock://localhost/database'))
|
@@ -41,21 +32,8 @@ describe DataObjects::Connection do
|
|
41
32
|
c.should be_kind_of(DataObjects::Mock::Connection)
|
42
33
|
|
43
34
|
c = DataObjects::Connection.new(Addressable::URI.parse('mock:jndi://jdbc/database'))
|
44
|
-
|
35
|
+
c.should be_kind_of(DataObjects::Mock::Connection)
|
45
36
|
end
|
46
37
|
|
47
|
-
it "should return the Connection using username" do
|
48
|
-
c = DataObjects::Connection.new(Addressable::URI.parse('mock://root@localhost/database'))
|
49
|
-
c.instance_variable_get(:@uri).user.should == 'root'
|
50
|
-
c.instance_variable_get(:@uri).password.should be_nil
|
51
|
-
|
52
|
-
c = DataObjects::Connection.new(Addressable::URI.parse('mock://root:@localhost/database'))
|
53
|
-
c.instance_variable_get(:@uri).user.should == 'root'
|
54
|
-
c.instance_variable_get(:@uri).password.should == ''
|
55
|
-
|
56
|
-
c = DataObjects::Connection.new(Addressable::URI.parse('mock://root:pwd@localhost/database'))
|
57
|
-
c.instance_variable_get(:@uri).user.should == 'root'
|
58
|
-
c.instance_variable_get(:@uri).password.should == 'pwd'
|
59
|
-
end
|
60
38
|
end
|
61
39
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec/runner/formatter/base_text_formatter'
|
2
|
+
|
3
|
+
# Code is based on standard SpecdocFormatter, but will print full error details as soon as they are found.
|
4
|
+
# Successful or pending examples are written only as a dot in the output. Header is only printed if errors occur.
|
5
|
+
#
|
6
|
+
# To use it, add the following to your spec/spec.opts:
|
7
|
+
# --require
|
8
|
+
# lib/rspec_immediate_feedback_formatter.rb
|
9
|
+
# --format
|
10
|
+
# Spec::Runner::Formatter::ImmediateFeedbackFormatter
|
11
|
+
|
12
|
+
module Spec
|
13
|
+
module Runner
|
14
|
+
module Formatter
|
15
|
+
class ImmediateFeedbackFormatter < BaseTextFormatter
|
16
|
+
|
17
|
+
def add_example_group(example_group)
|
18
|
+
super
|
19
|
+
@current_group = example_group.description
|
20
|
+
end
|
21
|
+
|
22
|
+
def example_failed(example, counter, failure)
|
23
|
+
if @current_group
|
24
|
+
output.puts
|
25
|
+
output.puts @current_group
|
26
|
+
@current_group = nil # only print the group name once
|
27
|
+
end
|
28
|
+
|
29
|
+
message = if failure.expectation_not_met?
|
30
|
+
"- #{example.description} (FAILED - #{counter})"
|
31
|
+
else
|
32
|
+
"- #{example.description} (ERROR - #{counter})"
|
33
|
+
end
|
34
|
+
|
35
|
+
output.puts(red(message))
|
36
|
+
dump_failure(counter, failure) # dump stacktrace immediately
|
37
|
+
output.flush
|
38
|
+
end
|
39
|
+
|
40
|
+
def example_passed(*)
|
41
|
+
output.print green('.')
|
42
|
+
output.flush
|
43
|
+
end
|
44
|
+
|
45
|
+
def example_pending(*)
|
46
|
+
super
|
47
|
+
output.print yellow('*')
|
48
|
+
output.flush
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/result_spec.rb
CHANGED
@@ -9,9 +9,6 @@ describe DataObjects::Result do
|
|
9
9
|
|
10
10
|
result = command.execute_non_query
|
11
11
|
|
12
|
-
# In case the driver needs to access the command or connection to load additional data.
|
13
|
-
result.instance_variables.map { |i| i.to_s }.should include('@command')
|
14
|
-
|
15
12
|
# Affected Rows:
|
16
13
|
result.should respond_to(:to_i)
|
17
14
|
result.to_i.should == 0
|