swift 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/swift/pool.rb CHANGED
@@ -17,12 +17,19 @@ module Swift
17
17
  @pool.detach self
18
18
  end
19
19
  end
20
+
21
+ def notify_writable
22
+ notify_readable
23
+ end
20
24
  end # Handler
21
25
 
22
26
 
23
27
  def initialize size, options
24
28
  @pool = Swift::DB::Pool.new size, options
25
- @stop_reactor = EM.reactor_running? ? false : true
29
+
30
+ # TODO move driver specific options to extension.
31
+ @writable = options[:driver] == 'db2'
32
+
26
33
  @pending = {}
27
34
  @queue = []
28
35
  end
@@ -33,9 +40,7 @@ module Swift
33
40
 
34
41
  def detach c
35
42
  @pending.delete(c)
36
- if @queue.empty?
37
- EM.stop if @stop_reactor && @pending.empty?
38
- else
43
+ unless @queue.empty?
39
44
  sql, bind, callback = @queue.shift
40
45
  execute(sql, *bind, &callback)
41
46
  end
@@ -54,7 +59,7 @@ module Swift
54
59
  if request && !attached?(request.socket)
55
60
  EM.watch(request.socket, Handler, request, self) do |c|
56
61
  attach c
57
- c.notify_writable = false
62
+ c.notify_writable = @writable
58
63
  c.notify_readable = true
59
64
  end
60
65
  else
data/lib/swift/type.rb CHANGED
@@ -3,7 +3,7 @@ module Swift
3
3
  class BigDecimal < Attribute; end
4
4
  class Boolean < Attribute; end
5
5
  class Date < Attribute; end
6
- class DateTime < Attribute; end
6
+ class Time < Attribute; end
7
7
  class Float < Attribute; end
8
8
  class Integer < Attribute; end
9
9
  class IO < Attribute; end
data/swift.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{swift}
8
- s.version = "0.6.1"
8
+ s.version = "0.7.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Shane Hanna", "Bharanee 'Barney' Rathna"]
12
- s.date = %q{2010-09-02}
12
+ s.date = %q{2010-09-20}
13
13
  s.description = %q{A rational rudimentary database abstraction.}
14
14
  s.email = ["shane.hanna@gmail.com", "deepfryed@gmail.com"]
15
15
  s.extensions = ["ext/extconf.rb"]
@@ -25,6 +25,8 @@ Gem::Specification.new do |s|
25
25
  "VERSION",
26
26
  "ext/adapter.cc",
27
27
  "ext/adapter.h",
28
+ "ext/attribute.cc",
29
+ "ext/attribute.h",
28
30
  "ext/extconf.rb",
29
31
  "ext/iostream.cc",
30
32
  "ext/iostream.h",
data/test/helper.rb CHANGED
@@ -3,23 +3,24 @@ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'minitest/spec'
4
4
  require 'minitest/unit'
5
5
  require 'swift'
6
+ require 'etc'
6
7
 
7
- class MiniTest::Unit::TestCase
8
- end
8
+ # db2 database name is limited to 8 characters, gonna use swift instead of swift_test
9
9
 
10
10
  class MiniTest::Spec
11
11
  def self.supported_by *adapters, &block
12
+ connection_defaults = { db: 'swift', user: Etc.getlogin, host: '127.0.0.1' }
12
13
  adapters.each do |adapter|
13
14
  begin
14
- Swift.setup :default, adapter, db: 'swift_test'
15
+ Swift.setup :default, adapter, connection_defaults
15
16
  rescue => error
16
- warn "Unable to setup 'swift_test' db for #{adapter}, #{error.message}. Skipping..."
17
+ warn "Unable to setup 'swift' db for #{adapter}, #{error.message}. Skipping..."
17
18
  next
18
19
  end
19
20
 
20
21
  describe("Adapter #{adapter.name}") do
21
22
  before do
22
- Swift.setup :default, adapter, db: 'swift_test'
23
+ Swift.setup :default, adapter, connection_defaults
23
24
  end
24
25
  block.call(adapter)
25
26
  end
data/test/test_adapter.rb CHANGED
@@ -2,122 +2,119 @@ require_relative 'helper'
2
2
  require 'stringio'
3
3
 
4
4
  describe 'Adapter' do
5
- supported_by Swift::DB::Postgres, Swift::DB::Mysql do
5
+ supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::DB2 do
6
6
  describe 'db' do
7
+ before do
8
+ @db = Swift.db
9
+ @db.execute('drop table users') rescue nil
10
+ type = case @db
11
+ when Swift::DB::DB2 then 'integer not null generated by default as identity'
12
+ else 'serial'
13
+ end
14
+ @db.execute %Q{create table users(id #{type}, name varchar(512), email varchar(512), created_at timestamp)}
15
+ end
16
+
7
17
  it 'yields db to block' do
8
18
  Swift.db do |db|
9
19
  assert_kind_of Swift::Adapter, db
10
20
  end
11
21
  end
12
- end
13
22
 
14
- describe 'execute' do
15
- it 'executes without bind values' do
16
- assert Swift.db.execute %q{drop table if exists users}
17
- end
23
+ describe 'execute' do
24
+ it 'executes without bind values' do
25
+ assert @db.execute %q{select count(*) from users}
26
+ end
18
27
 
19
- it 'executes with bind values' do
20
- Swift.db.execute %q{drop table if exists users}
21
- Swift.db.execute %q{create table users(id serial, name text, created_at timestamp)}
22
- assert Swift.db.execute 'insert into users (name, created_at) values (?, now())', 'Benny Arthurton'
28
+ it 'executes with bind values' do
29
+ assert @db.execute 'insert into users (name, created_at) values (?, current_timestamp)', 'Benny Arthurton'
30
+ end
23
31
  end
24
- end
25
32
 
26
- describe 'prepared statements' do
27
- before do
28
- @db = Swift.db do |db|
29
- db.execute %q{drop table if exists users}
30
- db.execute %q{create table users(id serial, name text, created_at timestamp)}
33
+ describe 'prepared statements' do
34
+ it 'executes via Statement#new' do
35
+ result = []
36
+ Swift::Statement.new(@db, 'select count(*) as n from users').execute {|r| result << r[:n] }
37
+ assert_kind_of Integer, result[0]
31
38
  end
32
- end
33
39
 
34
- it 'executes without bind values' do
35
- assert @db.prepare(%q{insert into users (name, created_at) values ('Apple Arthurton', now())}).execute
36
- end
40
+ it 'executes without bind values' do
41
+ assert @db.prepare(%q{insert into users (name) values ('Apple Arthurton')}).execute
42
+ end
37
43
 
38
- it 'executes with bind values' do
39
- assert @db.prepare(%q{insert into users (name, created_at) values (?, now())}).execute('Apple Arthurton')
40
- end
44
+ it 'executes with bind values' do
45
+ assert @db.prepare(%q{insert into users (name) values (?)}).execute('Apple Arthurton')
46
+ end
41
47
 
42
- it 'executes multiple times' do
43
- sth = @db.prepare(%q{insert into users (name, created_at) values (?, now())})
44
- assert sth.execute('Apple Arthurton')
45
- assert sth.execute('Benny Arthurton')
46
- end
48
+ it 'executes multiple times' do
49
+ sth = @db.prepare(%q{insert into users (name, created_at) values (?, current_timestamp)})
50
+ assert sth.execute('Apple Arthurton')
51
+ assert sth.execute('Benny Arthurton')
52
+ end
47
53
 
48
- it 'has insert_id' do
49
- sql = case @db
50
- when Swift::DB::Postgres then %q{insert into users (name, created_at) values (?, now()) returning id}
51
- when Swift::DB::Mysql then %q{insert into users (name, created_at) values (?, now())}
54
+ it 'has insert_id' do
55
+ sql = case @db
56
+ when Swift::DB::Postgres then %q{insert into users (name) values (?) returning id}
57
+ when Swift::DB::Mysql then %q{insert into users (name) values (?)}
58
+ when Swift::DB::DB2 then %q{select id from final table(insert into users(name) values(?))}
59
+ end
60
+ assert_kind_of Numeric, @db.prepare(sql).execute('Connie Arthurton').insert_id
52
61
  end
53
- assert_kind_of Numeric, @db.prepare(sql).execute('Connie Arthurton').insert_id
54
62
  end
55
- end
56
63
 
57
- describe 'executed prepared statements' do
58
- before do
59
- @db = Swift.db do |db|
60
- db.execute %q{drop table if exists users}
61
- db.execute %q{create table users(id serial, name text, created_at timestamp)}
62
- sth = db.prepare(%q{insert into users (name, created_at) values (?, now())})
63
- sth.execute('Apple Arthurton')
64
- sth.execute('Benny Arthurton')
65
- end
66
- @sth = @db.prepare('select * from users').execute
67
- end
64
+ describe 'executed prepared statements' do
65
+ before do
66
+ insert = @db.prepare(%q{insert into users (name, created_at) values (?, current_timestamp)})
67
+ insert.execute('Apple Arthurton')
68
+ insert.execute('Benny Arthurton')
69
+ @sth = @db.prepare('select * from users').execute
70
+ end
68
71
 
69
- it 'enumerates' do
70
- assert_kind_of Enumerable, @sth
71
- end
72
+ it 'enumerates' do
73
+ assert_kind_of Enumerable, @sth
74
+ end
72
75
 
73
- it 'enumerates block' do
74
- begin
75
- @sth.execute{|row| row}
76
- rescue => error
77
- flunk error.message
78
- else
79
- pass
76
+ it 'enumerates block' do
77
+ begin
78
+ @sth.execute{|row| row}
79
+ rescue => error
80
+ flunk error.message
81
+ else
82
+ pass
83
+ end
80
84
  end
81
- end
82
85
 
83
- it 'returns hash tuples for enumerable methods' do
84
- assert_kind_of Hash, @sth.first
85
- end
86
+ it 'returns hash tuples for enumerable methods' do
87
+ assert_kind_of Hash, @sth.first
88
+ end
86
89
 
87
- it 'returns a result set on Adapter#execute{}' do
88
- @db.execute('select * from users') {|r| assert_kind_of Hash, r }
89
- end
90
+ it 'returns a result set on Adapter#execute{}' do
91
+ @db.execute('select * from users') {|r| assert_kind_of Hash, r }
92
+ end
90
93
 
91
- it 'returns a result set on Adapter#results' do
92
- @db.execute('select * from users')
93
- assert_kind_of Swift::Result, @db.results
94
- end
94
+ it 'returns a result set on Adapter#results' do
95
+ @db.execute('select * from users')
96
+ assert_kind_of Swift::Result, @db.results
97
+ end
95
98
 
96
- it 'returns fields' do
97
- assert_equal [ :id, :name, :created_at ], @sth.fields
99
+ it 'returns fields' do
100
+ assert_equal [ :id, :name, :email, :created_at ], @sth.fields
101
+ end
98
102
  end
99
- end
100
103
 
101
104
 
102
- #--
103
- # TODO: Not sure how I feel about the block in write; feels like it's just there to get around the fields in the
104
- # argument list. How about write('users', %w{name, email, balance}, data)?
105
- describe 'bulk writes!' do
106
- before do
107
- @db = Swift.db do |db|
108
- db.execute %q{drop table if exists users}
109
- db.execute %q{create table users(id serial, name text, email text)}
105
+ #--
106
+ # TODO: Not sure how I feel about the block in write; feels like it's just there to get around the fields in the
107
+ # argument list. How about write('users', %w{name, email, balance}, data)?
108
+ describe 'bulk writes!' do
109
+ it 'writes from an IO object' do
110
+ data = StringIO.new "Sally Arthurton\tsally@local\nJonas Arthurton\tjonas@local\n"
111
+ assert_equal 2, @db.write('users', %w{name email}, data)
110
112
  end
111
- end
112
-
113
- it 'writes from an IO object' do
114
- data = StringIO.new "Sally Arthurton\tsally@local\nJonas Arthurton\tjonas@local\n"
115
- assert_equal 2, Swift.db.write('users', %w{name email}, data)
116
- end
117
113
 
118
- it 'writes from a string' do
119
- data = "Sally Arthurton\tsally@local\nJonas Arthurton\tjonas@local\n"
120
- assert_equal 2, Swift.db.write('users', %w{name email}, data)
114
+ it 'writes from a string' do
115
+ data = "Sally Arthurton\tsally@local\nJonas Arthurton\tjonas@local\n"
116
+ assert_equal 2, @db.write('users', %w{name email}, data)
117
+ end
121
118
  end
122
119
  end
123
120
  end
@@ -1,12 +1,12 @@
1
1
  require_relative 'helper'
2
2
 
3
3
  describe 'Adapter' do
4
- supported_by Swift::DB::Postgres, Swift::DB::Mysql do
4
+ supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::DB2 do
5
5
  describe 'character encoding' do
6
6
  before do
7
7
  Swift.db do |db|
8
- db.execute %q{drop table if exists users}
9
- db.execute %q{create table users(id serial, name text, primary key(id))}
8
+ db.execute %q{drop table users} rescue nil
9
+ db.execute %q{create table users(name varchar(128))}
10
10
 
11
11
  # Mysql on debian at least doesn't default to utf8.
12
12
  if db.kind_of? Swift::DB::Mysql
data/test/test_io.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require_relative 'helper'
2
2
 
3
3
  describe 'Adapter' do
4
- supported_by Swift::DB::Postgres, Swift::DB::Mysql do
4
+ supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::DB2 do
5
5
  describe 'Storing binary objects' do
6
6
  before do
7
7
  user = Class.new(Swift::Scheme) do
data/test/test_pool.rb CHANGED
@@ -6,28 +6,32 @@ describe 'Adapter' do
6
6
  describe 'Asynchronous connection pool' do
7
7
  before do
8
8
  Swift.db do |db|
9
- db.execute %q{drop table if exists users}
10
- db.execute %Q{create table users(id serial, name text)}
9
+ db.execute %q{drop table users} rescue nil
10
+ db.execute %Q{create table users(name varchar(64))}
11
11
  end
12
12
  end
13
13
 
14
- it 'creates connection pool' do
15
- driver = Swift.db.kind_of?(Swift::DB::Mysql) ? 'mysql' : 'postgresql'
16
- assert Swift::Pool.new 5, db: 'swift_test', driver: driver
17
- end
18
-
19
- describe 'Running queries' do
20
- it 'should select data' do
21
- rows = []
14
+ it 'creates connection pool and runs queries' do
15
+ rows = []
16
+ Swift.pool(5) do |pool|
17
+ assert pool
22
18
  assert Swift.db.write('users', %w{name}, StringIO.new("user1\nuser2\nuser3\n"))
23
- Swift.pool 5 do |pool|
24
- pool.execute('select * from users') do |rs|
25
- rows += rs.to_a
26
- pool.execute('select * from users') {|rs| rows += rs.to_a }
19
+ pool.execute('select * from users') do |rs|
20
+ rows += rs.to_a
21
+ Thread.new do
22
+ sleep 0.25
23
+ pool.execute('select * from users order by name desc') {|rs| rows += rs.to_a; EM.stop }
27
24
  end
28
25
  end
29
- assert_equal 6, rows.length
26
+ pool.execute('select * from users') do |rs|
27
+ rows += rs.to_a
28
+ end
30
29
  end
30
+
31
+ data = %w(user1 user2 user3)
32
+
33
+ assert_equal 9, rows.length
34
+ assert_equal data*2 + data.reverse, rows.map {|r| r[:name] }
31
35
  end
32
36
  end
33
37
  end
data/test/test_scheme.rb CHANGED
@@ -9,7 +9,7 @@ describe 'scheme' do
9
9
  attribute :age, Swift::Type::Integer, default: 18
10
10
  attribute :email, Swift::Type::String
11
11
  attribute :verified, Swift::Type::Boolean, default: false
12
- attribute :created_at, Swift::Type::DateTime, default: proc { Time.now }
12
+ attribute :created_at, Swift::Type::Time, default: proc { Time.now }
13
13
  end
14
14
  end
15
15
 
@@ -25,15 +25,32 @@ describe 'Adapter' do
25
25
  assert_timestamp_like time, fetch_timestamp_at(time), 'DST off'
26
26
  end
27
27
 
28
- def fetch_timestamp_at value
29
- sql = "select '%s'::timestamp with time zone as now" % value.strftime('%F %T%z')
28
+ describe 'Adapter timezone' do
29
+ %w(+05:30 -05:30).each do |offset|
30
+ it 'should parse timestamps and do conversion accordingly for offset ' + offset do
31
+ @db = Swift::DB::Postgres.new(@db.options.merge(timezone: offset))
32
+ server = DateTime.parse('2010-01-01 10:00:00')
33
+ local = DateTime.parse('2010-01-01 10:00:00 ' + offset)
34
+ assert_timestamp_like local, fetch_timestamp_at(server, ''), 'parses correctly'
35
+ end
36
+ end
37
+ end
38
+
39
+ def fetch_timestamp_at value, zone='%z'
40
+ sql = if zone.empty?
41
+ "select '%s'::timestamp as now"
42
+ else
43
+ "select '%s'::timestamp with time zone as now"
44
+ end
45
+
46
+ sql = sql % value.strftime('%F %T' + zone)
30
47
  @db.execute(sql)
31
48
  @db.results.first.fetch(:now)
32
49
  end
33
50
 
34
51
  def assert_timestamp_like expect, given, comment
35
52
  match = Regexp.new expect.to_time.strftime('%F %T')
36
- assert_kind_of DateTime, given
53
+ assert_kind_of Time, given
37
54
  assert_match match, given.strftime('%F %T'), comment
38
55
  end
39
56
  end
@@ -1,15 +1,15 @@
1
1
  require_relative 'helper'
2
- describe 'Adapter' do
3
- supported_by Swift::DB::Postgres do #, Swift::DB::Mysql do
4
- before do
5
- Swift.db.execute %q{drop table if exists users}
6
- Swift.db.execute %q{create table users(id serial, name text, created_at timestamp)}
7
- end
8
2
 
3
+ describe 'Adapter' do
4
+ supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::DB2 do
9
5
  describe 'transactions' do
10
6
  before do
11
7
  @name = 'test1 - transaction 1'
12
8
  @db = Swift.db
9
+ @db.execute %q{drop table users} rescue nil
10
+ @db.execute %q{create table users(name varchar(512), created_at timestamp)}
11
+ @db.execute %q{alter table users engine=innodb} if @db.kind_of?(Swift::DB::Mysql) # In case of MyISAM default.
12
+ @sth = @db.prepare('select count(*) as c from users where name = ?')
13
13
  end
14
14
 
15
15
  it 'yields db to block' do
@@ -28,7 +28,7 @@ describe 'Adapter' do
28
28
  end
29
29
 
30
30
  after do
31
- @db.execute('select count(*) as c from users where name = ?', @name) {|r| assert_equal 1, r[:c] }
31
+ assert_equal 1, @sth.execute(@name).first[:c]
32
32
  end
33
33
 
34
34
  it 'should allow explicit commits' do
@@ -43,16 +43,15 @@ describe 'Adapter' do
43
43
  db.execute('insert into users(name) values(?)', @name)
44
44
  end
45
45
  end
46
- end
46
+ end # commits work
47
47
 
48
48
  describe 'rollbacks work' do
49
-
50
49
  before do
51
50
  @db.execute('truncate users')
52
51
  end
53
52
 
54
53
  after do
55
- @db.execute('select count(*) as c from users where name = ?', @name) {|r| assert_equal 0, r[:c] }
54
+ assert_equal 0, @sth.execute(@name).first[:c]
56
55
  end
57
56
 
58
57
  it 'should allow explicit rollbacks' do
@@ -70,7 +69,31 @@ describe 'Adapter' do
70
69
  end
71
70
  end
72
71
  end
73
- end
74
- end
75
- end
76
- end
72
+ end # rollbacks work
73
+
74
+ describe 'nested transactions' do
75
+ before do
76
+ @db.execute('truncate users')
77
+ end
78
+
79
+ after do
80
+ assert_equal 1, @sth.execute(@name).first[:c]
81
+ end
82
+
83
+ it 'should autocommit and autorollback' do
84
+ @db.transaction do |db|
85
+ db.execute('insert into users(name) values(?)', @name)
86
+ begin
87
+ db.transaction do
88
+ db.execute('insert into users(name) values(?)', @name)
89
+ raise 'foo'
90
+ end
91
+ rescue RuntimeError
92
+ end
93
+ end
94
+ end
95
+ end # nested transactions
96
+
97
+ end # transactions
98
+ end # supported_by
99
+ end # adapter
data/test/test_types.rb CHANGED
@@ -7,13 +7,23 @@ describe 'Adapter' do
7
7
  @db = Swift.db
8
8
  @db.execute %q{drop table if exists users}
9
9
  @db.execute %q{
10
- create table users(id serial, name text, age integer, height float, hacker bool, slacker bool, created date)
10
+ create table users(
11
+ id serial,
12
+ name text,
13
+ age integer,
14
+ height float,
15
+ hacker bool,
16
+ slacker bool,
17
+ created date,
18
+ updated timestamp
19
+ )
11
20
  }
12
21
  end
13
22
 
14
23
  it 'query result is typecast correctly' do
15
- bind = [ 'jim', 32, 178.71, true, false ]
16
- @db.execute %q{insert into users(name,age,height,hacker,slacker, created) values(?, ?, ?, ?, ?, now())}, *bind
24
+ dt = '2010-01-01 23:22:21'
25
+ bind = [ 1, 'jim', 32, 178.71, true, false, '2010-01-02', "#{dt}.012345+11:00" ]
26
+ @db.execute %q{insert into users values(?, ?, ?, ?, ?, ?, ?, ?)}, *bind
17
27
 
18
28
  result = @db.prepare(%q{select * from users limit 1}).execute.first
19
29
  assert_kind_of Integer, result[:id]
@@ -23,6 +33,10 @@ describe 'Adapter' do
23
33
  assert_kind_of TrueClass, result[:hacker]
24
34
  assert_kind_of FalseClass, result[:slacker]
25
35
  assert_kind_of Date, result[:created]
36
+ assert_kind_of Time, result[:updated]
37
+
38
+ assert_equal dt, result[:updated].strftime('%F %T')
39
+ assert_equal 12345, result[:updated].usec if @db.kind_of?(Swift::DB::Postgres)
26
40
  end
27
41
  end
28
42
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 6
8
- - 1
9
- version: 0.6.1
7
+ - 7
8
+ - 0
9
+ version: 0.7.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Shane Hanna
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-02 00:00:00 +10:00
18
+ date: 2010-09-20 00:00:00 +10:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -63,6 +63,8 @@ files:
63
63
  - VERSION
64
64
  - ext/adapter.cc
65
65
  - ext/adapter.h
66
+ - ext/attribute.cc
67
+ - ext/attribute.h
66
68
  - ext/extconf.rb
67
69
  - ext/iostream.cc
68
70
  - ext/iostream.h