swift 0.6.1 → 0.7.0

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/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