data_objects 0.10.3 → 0.10.4.rc1

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.
Files changed (50) hide show
  1. data/LICENSE +1 -1
  2. data/README.markdown +1 -1
  3. data/Rakefile +6 -32
  4. data/lib/data_objects/connection.rb +9 -6
  5. data/lib/data_objects/pooling.rb +1 -1
  6. data/lib/data_objects/spec/lib/pending_helpers.rb +11 -0
  7. data/lib/data_objects/spec/{helpers → lib}/ssl.rb +0 -0
  8. data/lib/data_objects/spec/setup.rb +5 -0
  9. data/lib/data_objects/spec/{command_spec.rb → shared/command_spec.rb} +54 -50
  10. data/lib/data_objects/spec/shared/connection_spec.rb +245 -0
  11. data/lib/data_objects/spec/{encoding_spec.rb → shared/encoding_spec.rb} +41 -43
  12. data/lib/data_objects/spec/shared/error/sql_error_spec.rb +30 -0
  13. data/lib/data_objects/spec/{quoting_spec.rb → shared/quoting_spec.rb} +0 -0
  14. data/lib/data_objects/spec/{reader_spec.rb → shared/reader_spec.rb} +31 -26
  15. data/lib/data_objects/spec/shared/result_spec.rb +79 -0
  16. data/lib/data_objects/spec/{typecast → shared/typecast}/array_spec.rb +4 -2
  17. data/lib/data_objects/spec/{typecast → shared/typecast}/bigdecimal_spec.rb +12 -8
  18. data/lib/data_objects/spec/{typecast → shared/typecast}/boolean_spec.rb +14 -10
  19. data/lib/data_objects/spec/{typecast → shared/typecast}/byte_array_spec.rb +6 -4
  20. data/lib/data_objects/spec/{typecast → shared/typecast}/class_spec.rb +5 -3
  21. data/lib/data_objects/spec/{typecast → shared/typecast}/date_spec.rb +13 -9
  22. data/lib/data_objects/spec/{typecast → shared/typecast}/datetime_spec.rb +14 -11
  23. data/lib/data_objects/spec/{typecast → shared/typecast}/float_spec.rb +17 -13
  24. data/lib/data_objects/spec/{typecast → shared/typecast}/integer_spec.rb +7 -5
  25. data/lib/data_objects/spec/{typecast → shared/typecast}/ipaddr_spec.rb +0 -0
  26. data/lib/data_objects/spec/{typecast → shared/typecast}/nil_spec.rb +23 -17
  27. data/lib/data_objects/spec/{typecast → shared/typecast}/other_spec.rb +11 -9
  28. data/lib/data_objects/spec/{typecast → shared/typecast}/range_spec.rb +4 -2
  29. data/lib/data_objects/spec/{typecast → shared/typecast}/string_spec.rb +10 -8
  30. data/lib/data_objects/spec/{typecast → shared/typecast}/time_spec.rb +44 -6
  31. data/lib/data_objects/transaction.rb +9 -0
  32. data/lib/data_objects/uri.rb +62 -4
  33. data/lib/data_objects/version.rb +1 -1
  34. data/spec/command_spec.rb +2 -2
  35. data/spec/connection_spec.rb +45 -25
  36. data/spec/pooling_spec.rb +9 -9
  37. data/spec/reader_spec.rb +11 -12
  38. data/spec/result_spec.rb +13 -11
  39. data/spec/spec_helper.rb +1 -16
  40. data/spec/transaction_spec.rb +9 -11
  41. data/spec/uri_spec.rb +35 -27
  42. data/tasks/spec.rake +8 -17
  43. metadata +40 -56
  44. data/lib/data_objects/spec/bacon.rb +0 -9
  45. data/lib/data_objects/spec/connection_spec.rb +0 -217
  46. data/lib/data_objects/spec/error/sql_error_spec.rb +0 -19
  47. data/lib/data_objects/spec/helpers/immediate_red_green_output.rb +0 -59
  48. data/lib/data_objects/spec/helpers/pending.rb +0 -22
  49. data/lib/data_objects/spec/result_spec.rb +0 -79
  50. data/tasks/metrics.rake +0 -36
@@ -10,20 +10,22 @@ class ::CustomTextType
10
10
 
11
11
  end
12
12
 
13
- shared 'supporting other (unknown) type' do
13
+ shared_examples_for 'supporting other (unknown) type' do
14
14
 
15
- setup_test_environment
16
-
17
- before do
18
- @connection = DataObjects::Connection.new(CONFIG.uri)
19
- end
20
-
21
- after do
22
- @connection.close
15
+ before :all do
16
+ setup_test_environment
23
17
  end
24
18
 
25
19
  describe 'writing an object of unknown type' do
26
20
 
21
+ before do
22
+ @connection = DataObjects::Connection.new(CONFIG.uri)
23
+ end
24
+
25
+ after do
26
+ @connection.close
27
+ end
28
+
27
29
  before do
28
30
  @command = @connection.create_command("SELECT ad_description FROM widgets WHERE ad_description = ?")
29
31
  @command.set_types(::CustomTextType)
@@ -1,6 +1,8 @@
1
- shared 'supporting Range' do
1
+ shared_examples_for 'supporting Range' do
2
2
 
3
- setup_test_environment
3
+ before :all do
4
+ setup_test_environment
5
+ end
4
6
 
5
7
  before do
6
8
  @connection = DataObjects::Connection.new(CONFIG.uri)
@@ -1,8 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
- shared 'supporting String' do
3
+ shared_examples_for 'supporting String' do
4
4
 
5
- setup_test_environment
5
+ before :all do
6
+ setup_test_environment
7
+ end
6
8
 
7
9
  before do
8
10
  @connection = DataObjects::Connection.new(CONFIG.uri)
@@ -27,7 +29,7 @@ shared 'supporting String' do
27
29
  end
28
30
 
29
31
  it 'should return the correctly typed result' do
30
- @values.first.should.be.kind_of(String)
32
+ @values.first.should be_kind_of(String)
31
33
  end
32
34
 
33
35
  it 'should return the correct result' do
@@ -51,7 +53,7 @@ shared 'supporting String' do
51
53
  end
52
54
 
53
55
  it 'should return the correctly typed result' do
54
- @values.first.should.be.kind_of(String)
56
+ @values.first.should be_kind_of(String)
55
57
  end
56
58
 
57
59
  it 'should return the correct result' do
@@ -76,7 +78,7 @@ shared 'supporting String' do
76
78
 
77
79
  it 'should return the correct entry' do
78
80
  # Some of the drivers starts autoincrementation from 0 not 1
79
- @values.first.should.satisfy { |val| val == 1 or val == 2 }
81
+ @values.first.should satisfy { |val| val == 1 or val == 2 }
80
82
  end
81
83
 
82
84
  end
@@ -94,7 +96,7 @@ shared 'supporting String' do
94
96
 
95
97
  it 'should write a multibyte String' do
96
98
  @command = @connection.create_command('INSERT INTO users (name) VALUES(?)')
97
- should.not.raise(DataObjects::DataError) { @command.execute_non_query(name) }
99
+ expect { @command.execute_non_query(name) }.not_to raise_error(DataObjects::DataError)
98
100
  end
99
101
 
100
102
  it 'should read back the multibyte String' do
@@ -107,7 +109,7 @@ shared 'supporting String' do
107
109
 
108
110
  it 'should write a multibyte String (without query parameters)' do
109
111
  @command = @connection.create_command("INSERT INTO users (name) VALUES(#{@n}\'#{name}\')")
110
- should.not.raise(DataObjects::DataError) { @command.execute_non_query }
112
+ expect { @command.execute_non_query }.not_to raise_error(DataObjects::DataError)
111
113
  end
112
114
 
113
115
  it 'should read back the multibyte String (without query parameters)' do
@@ -137,7 +139,7 @@ shared 'supporting String' do
137
139
 
138
140
  it 'should return the correct entry' do
139
141
  # Some of the drivers starts autoincrementation from 0 not 1
140
- @values.first.should.satisfy { |val| val == 1 or val == 2 }
142
+ @values.first.should satisfy { |val| val == 1 or val == 2 }
141
143
  end
142
144
 
143
145
  end
@@ -1,6 +1,8 @@
1
- shared 'supporting Time' do
1
+ shared_examples_for 'supporting Time' do
2
2
 
3
- setup_test_environment
3
+ before :all do
4
+ setup_test_environment
5
+ end
4
6
 
5
7
  before do
6
8
  @connection = DataObjects::Connection.new(CONFIG.uri)
@@ -27,7 +29,7 @@ shared 'supporting Time' do
27
29
  end
28
30
 
29
31
  it 'should return the correctly typed result' do
30
- @values.first.should.be.kind_of(Time)
32
+ @values.first.should be_kind_of(Time)
31
33
  end
32
34
 
33
35
  it 'should return the correct result' do
@@ -51,11 +53,11 @@ shared 'supporting Time' do
51
53
  end
52
54
 
53
55
  it 'should return a nil class' do
54
- @values.first.should.be.kind_of(NilClass)
56
+ @values.first.should be_kind_of(NilClass)
55
57
  end
56
58
 
57
59
  it 'should return nil' do
58
- @values.first.should.be.nil
60
+ @values.first.should be_nil
59
61
  end
60
62
 
61
63
  end
@@ -76,9 +78,45 @@ shared 'supporting Time' do
76
78
 
77
79
  it 'should return the correct entry' do
78
80
  #Some of the drivers starts autoincrementation from 0 not 1
79
- @values.first.should.satisfy { |val| val == 1 or val == 0 }
81
+ @values.first.should satisfy { |val| val == 1 or val == 0 }
80
82
  end
81
83
 
82
84
  end
83
85
 
84
86
  end
87
+
88
+ shared_examples_for 'supporting sub second Time' do
89
+
90
+ before :all do
91
+ setup_test_environment
92
+ end
93
+
94
+ before do
95
+ @connection = DataObjects::Connection.new(CONFIG.uri)
96
+ @connection.create_command(<<-EOF).execute_non_query(Time.parse('2010-12-15 14:32:08.49377-08'))
97
+ update widgets set release_timestamp = ? where id = 1
98
+ EOF
99
+ @connection.create_command(<<-EOF).execute_non_query(Time.parse('2010-12-15 14:32:28.942694-08'))
100
+ update widgets set release_timestamp = ? where id = 2
101
+ EOF
102
+
103
+ @command = @connection.create_command("SELECT release_timestamp FROM widgets WHERE id < ? order by id")
104
+ @command.set_types(Time)
105
+ @reader = @command.execute_reader(3)
106
+ @reader.next!
107
+ @values = @reader.values
108
+ end
109
+
110
+ after do
111
+ @connection.close
112
+ end
113
+
114
+ it 'should handle variable subsecond lengths properly' do
115
+ @values.first.should == Time.at(1292452328, 493770)
116
+
117
+ @reader.next!
118
+ @values = @reader.values
119
+ @values.first.should == Time.at(1292452348, 942694)
120
+ end
121
+
122
+ end
@@ -72,6 +72,15 @@ module DataObjects
72
72
  DataObjects::SavePoint.new(uri, connection)
73
73
  end
74
74
 
75
+ # SavePoints can only occur in the context of a Transaction, thus they
76
+ # re-use TXN's connection (which was acquired from the connection pool
77
+ # legitimately via DO::Connection.new). We no-op #close in SP because
78
+ # calling DO::Connection#close will release the connection back into the
79
+ # pool (before the top-level Transaction might be done with it).
80
+ def close
81
+ # no-op
82
+ end
83
+
75
84
  def begin
76
85
  run %{SAVEPOINT "#{@id}"}
77
86
  end
@@ -13,18 +13,75 @@ module DataObjects
13
13
  # path:: The name or path to the database
14
14
  # query:: Parameters for the connection, for example encoding=utf8
15
15
  # fragment:: Not currently known to be in use, but available to the adapters
16
- class URI < Struct.new(:scheme, :user, :password, :host, :port, :path, :query, :fragment)
16
+ class URI
17
+ attr_reader :scheme, :subscheme, :user, :password, :host, :port, :path, :query, :fragment
18
+
17
19
  # Make a DataObjects::URI object by parsing a string. Simply delegates to Addressable::URI::parse.
18
20
  def self.parse(uri)
19
21
  return uri if uri.kind_of?(self)
20
- uri = Addressable::URI::parse(uri) unless uri.kind_of?(Addressable::URI)
21
- self.new(uri.scheme, uri.user, uri.password, uri.host, uri.port, uri.path, uri.query_values, uri.fragment)
22
+
23
+ if uri.kind_of?(Addressable::URI)
24
+ scheme = uri.scheme
25
+ else
26
+ if uri[0,4] == 'jdbc'
27
+ scheme = uri[0,4]
28
+ uri = Addressable::URI::parse(uri[5, uri.length])
29
+ subscheme = uri.scheme
30
+ else
31
+ uri = Addressable::URI::parse(uri)
32
+ scheme = uri.scheme
33
+ subscheme = nil
34
+ end
35
+ end
36
+
37
+ self.new(
38
+ :scheme => scheme,
39
+ :subscheme => subscheme,
40
+ :user => uri.user,
41
+ :password => uri.password,
42
+ :host => uri.host,
43
+ :port => uri.port,
44
+ :path => uri.path,
45
+ :query => uri.query_values,
46
+ :fragment => uri.fragment,
47
+ :relative => !!uri.to_s.index('//') # basic (naive) check for relativity / opaqueness
48
+ )
49
+ end
50
+
51
+ def initialize(*args)
52
+ if (component = args.first).kind_of?(Hash)
53
+ @scheme = component[:scheme]
54
+ @subscheme = component[:subscheme]
55
+ @user = component[:user]
56
+ @password = component[:password]
57
+ @host = component[:host]
58
+ @port = component[:port]
59
+ @path = component[:path]
60
+ @query = component[:query]
61
+ @fragment = component[:fragment]
62
+ @relative = component[:relative]
63
+ elsif args.size > 1
64
+ warn "DataObjects::URI.new with arguments is deprecated, use a Hash of URI components (#{caller.first})"
65
+ @scheme, @user, @password, @host, @port, @path, @query, @fragment = *args
66
+ else
67
+ raise ArgumentError, "argument should be a Hash of URI components, was: #{args.inspect}"
68
+ end
69
+ end
70
+
71
+ def opaque?
72
+ !@relative
73
+ end
74
+
75
+ def relative?
76
+ @relative
22
77
  end
23
78
 
24
79
  # Display this URI object as a string
25
80
  def to_s
26
81
  string = ""
27
- string << "#{scheme}://" if scheme
82
+ string << "#{scheme}:" if scheme
83
+ string << "#{subscheme}:" if subscheme
84
+ string << '//' if relative?
28
85
  if user
29
86
  string << "#{user}"
30
87
  string << ":#{password}" if password
@@ -51,5 +108,6 @@ module DataObjects
51
108
  def hash
52
109
  to_s.hash
53
110
  end
111
+
54
112
  end
55
113
  end
@@ -1,3 +1,3 @@
1
1
  module DataObjects
2
- VERSION = '0.10.3'
2
+ VERSION = '0.10.4.rc1'
3
3
  end
data/spec/command_spec.rb CHANGED
@@ -12,13 +12,13 @@ describe DataObjects::Command do
12
12
 
13
13
  %w{connection execute_non_query execute_reader set_types}.each do |meth|
14
14
  it "should respond to ##{meth}" do
15
- @command.should.respond_to(meth.intern)
15
+ @command.should respond_to(meth.intern)
16
16
  end
17
17
  end
18
18
 
19
19
  %w{execute_non_query execute_reader set_types}.each do |meth|
20
20
  it "should raise NotImplementedError on ##{meth}" do
21
- should.raise(NotImplementedError) { @command.send(meth.intern, nil) }
21
+ lambda { @command.send(meth.intern, nil) }.should raise_error(NotImplementedError)
22
22
  end
23
23
  end
24
24
 
@@ -1,41 +1,61 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require 'stringio'
2
3
 
3
4
  describe DataObjects::Connection do
4
- before do
5
- @connection = DataObjects::Connection.new('mock://localhost')
6
- end
5
+ subject { connection }
7
6
 
8
- after do
9
- @connection.release
10
- end
7
+ let(:connection) { described_class.new(uri) }
11
8
 
12
- %w{dispose create_command}.each do |meth|
13
- it "should respond to ##{meth}" do
14
- @connection.should.respond_to(meth.intern)
15
- end
16
- end
9
+ after { connection.close }
10
+
11
+ context 'should define a standard API' do
12
+ let(:uri) { 'mock://localhost' }
13
+
14
+ it { should respond_to(:dispose) }
15
+ it { should respond_to(:create_command) }
17
16
 
18
- it "should have #to_s that returns the connection uri string" do
19
- @connection.to_s.should == 'mock://localhost'
17
+ its(:to_s) { should == 'mock://localhost' }
20
18
  end
21
19
 
22
- describe "initialization" do
20
+ describe 'initialization' do
23
21
 
24
- it "should accept a connection uri as a Addressable::URI" do
25
- c = DataObjects::Connection.new(Addressable::URI::parse('mock://localhost/database'))
26
- # relying on the fact that mock connection sets @uri
27
- c.to_s.should == 'mock://localhost/database'
22
+ context 'with a connection uri as a Addressable::URI' do
23
+ let(:uri) { Addressable::URI::parse('mock://localhost/database') }
24
+
25
+ it { should be_kind_of(DataObjects::Mock::Connection) }
26
+ it { should be_kind_of(DataObjects::Pooling) }
27
+
28
+ its(:to_s) { should == 'mock://localhost/database' }
28
29
  end
29
30
 
30
- it "should return the Connection specified by the scheme" do
31
- c = DataObjects::Connection.new(Addressable::URI.parse('mock://localhost/database'))
32
- c.should.be.kind_of(DataObjects::Mock::Connection)
33
- c.should.be.kind_of(DataObjects::Pooling)
31
+ [
32
+ 'java:comp/env/jdbc/DataSource?driver=mock2',
33
+ Addressable::URI.parse('java:comp/env/jdbc/DataSource?driver=mock2')
34
+ ].each do |jndi_url|
35
+ context 'should return the Connection specified by the scheme without pooling' do
36
+ let(:uri) { jndi_url }
37
+
38
+ it { should be_kind_of(DataObjects::Mock2::Connection) }
39
+ it { should_not be_kind_of(DataObjects::Pooling) }
34
40
  end
41
+ end
35
42
 
36
- it "should return the Connection specified by the scheme without pooling" do
37
- c = DataObjects::Connection.new(Addressable::URI.parse('java://jdbc/database?scheme=mock2'))
38
- c.should.not.be.kind_of(DataObjects::Pooling)
43
+ %w(
44
+ jdbc:mock:memory::
45
+ jdbc:mock://host/database
46
+ jdbc:mock://host:6969/database
47
+ jdbc:mock:thin:host:database
48
+ jdbc:mock:thin:@host.domain.com:6969:database
49
+ jdbc:mock://server:6969/database;property=value;
50
+ jdbc:mock://[1111:2222:3333:4444:5555:6666:7777:8888]/database
51
+ ).each do |jdbc_url|
52
+ context "with JDBC URL '#{jdbc_url}'" do
53
+ let(:uri) { jdbc_url }
54
+
55
+ it { should be_kind_of(DataObjects::Mock::Connection) }
56
+ end
39
57
  end
58
+
40
59
  end
60
+
41
61
  end
data/spec/pooling_spec.rb CHANGED
@@ -64,7 +64,7 @@ describe "DataObjects::Pooling" do
64
64
  end
65
65
  end
66
66
 
67
- after do
67
+ after :each do
68
68
  DataObjects::Pooling.lock.synchronize do
69
69
  DataObjects::Pooling.pools.each do |pool|
70
70
  pool.lock.synchronize do
@@ -95,24 +95,24 @@ describe "DataObjects::Pooling" do
95
95
  it "should track the initialized pools" do
96
96
  bob = Person.new('Bob') # Ensure the pool is "primed"
97
97
  bob.name.should == 'Bob'
98
- bob.instance_variable_get(:@__pool).should.not.be.nil
98
+ bob.instance_variable_get(:@__pool).should_not be_nil
99
99
  Person.__pools.size.should == 1
100
100
  bob.release
101
101
  Person.__pools.size.should == 1
102
102
 
103
- DataObjects::Pooling::pools.should.not.be.empty
103
+ DataObjects::Pooling::pools.should_not be_empty
104
104
 
105
105
  sleep(1.2)
106
106
 
107
107
  # NOTE: This assertion is commented out, as our MockConnection objects are
108
108
  # currently in the pool.
109
- DataObjects::Pooling::pools.should.be.empty
110
- bob.name.should == nil
109
+ # DataObjects::Pooling::pools.should be_empty
110
+ bob.name.should be_nil
111
111
  end
112
112
 
113
113
  it "should allow you to overwrite Class#new" do
114
114
  bob = Overwriter.new('Bob')
115
- bob.should.be.overwritten
115
+ bob.should be_overwritten
116
116
  bob.release
117
117
  end
118
118
 
@@ -127,7 +127,7 @@ describe "DataObjects::Pooling" do
127
127
  bob = Person.new('Bob')
128
128
  t1.join
129
129
  bob.release
130
- end.should.not.raise(DataObjects::Pooling::InvalidResourceError)
130
+ end.should_not raise_error(DataObjects::Pooling::InvalidResourceError)
131
131
  end
132
132
 
133
133
  it "should allow you to flush a pool" do
@@ -141,7 +141,7 @@ describe "DataObjects::Pooling" do
141
141
  Overwriter.__pools[['Bob']].flush!
142
142
  Overwriter.__pools[['Bob']].size.should == 0
143
143
 
144
- bob.name.should.be.nil
144
+ bob.name.should be_nil
145
145
  end
146
146
 
147
147
  it "should wake up the scavenger thread when exiting" do
@@ -149,7 +149,7 @@ describe "DataObjects::Pooling" do
149
149
  bob.release
150
150
  DataObjects.exiting = true
151
151
  sleep(0.1)
152
- DataObjects::Pooling.scavenger?.should.be.false
152
+ DataObjects::Pooling.scavenger?.should be_false
153
153
  end
154
154
 
155
155
  it "should be able to detach an instance from the pool" do