swift 0.13.0 → 0.14.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.
@@ -0,0 +1,28 @@
1
+ require_relative 'helper'
2
+
3
+ describe 'Adapter' do
4
+ supported_by Swift::DB::Postgres do
5
+ describe 'async operations' do
6
+ it 'can runs queries async' do
7
+ rows = []
8
+ pool = 3.times.map.with_index {|n| Swift.setup n, Swift::DB::Postgres, db: 'swift' }
9
+
10
+ Thread.new do
11
+ pool[0].async_execute('select pg_sleep(0.3), 1 as query_id') {|row| rows << row[:query_id]}
12
+ end
13
+
14
+ Thread.new do
15
+ pool[1].async_execute('select pg_sleep(0.2), 2 as query_id') {|row| rows << row[:query_id]}
16
+ end
17
+
18
+ Thread.new do
19
+ pool[2].async_execute('select pg_sleep(0.1), 3 as query_id') {|row| rows << row[:query_id]}
20
+ end
21
+
22
+ Thread.list.reject {|thread| Thread.current == thread}.each(&:join)
23
+
24
+ assert_equal [3, 2, 1], rows
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'helper'
2
+
3
+ describe 'DateTimeParser' do
4
+ it 'should handle ymd style values' do
5
+ text = "2011-12-31 09:01:02.80300899 +1100"
6
+ time = DateTime.parse(text)
7
+ result = Swift::DateTime.parse(text)
8
+
9
+ assert_equal time.strftime('%F %T %z'), result.strftime('%F %T %z')
10
+ assert_equal time.second_fraction.to_f.round(8), result.second_fraction.to_f.round(8)
11
+ end
12
+ end
data/test/test_error.rb CHANGED
@@ -23,4 +23,27 @@ describe 'Error' do
23
23
  end
24
24
  end
25
25
  end
26
+
27
+ supported_by Swift::DB::Postgres do
28
+ describe 'execute' do
29
+ before do
30
+ Swift.db do |db|
31
+ db.execute %q{drop table if exists users}
32
+ db.execute %q{create table users(id integer, name text, primary key(id))}
33
+ end
34
+ end
35
+
36
+ it 'throws connection error on connection failures' do
37
+ select1 = Swift.db.prepare("select * from users")
38
+ select2 = Swift.db.prepare("select * from users where id > ?")
39
+
40
+ Swift.db.close
41
+
42
+ assert_raises(SwiftConnectionError) { select1.execute }
43
+ assert_raises(SwiftConnectionError) { select2.execute(1) }
44
+ assert_raises(SwiftConnectionError) { Swift.db.execute("select * from users") }
45
+ assert_raises(SwiftConnectionError) { Swift.db.execute("select * from users where id > ?", 1) }
46
+ end
47
+ end
48
+ end
26
49
  end
data/test/test_scheme.rb CHANGED
@@ -10,7 +10,7 @@ describe 'scheme' do
10
10
  attribute :height, Swift::Type::Float, default: 172.25
11
11
  attribute :email, Swift::Type::String
12
12
  attribute :verified, Swift::Type::Boolean, default: false
13
- attribute :created_at, Swift::Type::Time, default: proc { Time.now }
13
+ attribute :created_at, Swift::Type::DateTime, default: proc { Time.now }
14
14
 
15
15
  migrations do |db|
16
16
  db.execute %q{
@@ -1,13 +1,18 @@
1
1
  require_relative 'helper'
2
- require 'date'
3
2
 
4
3
  describe 'Adapter' do
5
4
  supported_by Swift::DB::Postgres do
6
5
  %w(America/Chicago Australia/Melbourne).each do |timezone|
7
6
  describe 'time parsing in %s' % timezone do
8
7
  before do
9
- @db = Swift.db
10
8
  ENV['TZ'] = ":#{timezone}"
9
+ @db = Swift.db
10
+ @db.execute 'create table datetime_test(id serial, ts timestamp with time zone)'
11
+ @db.execute "set time zone '#{timezone}'"
12
+ end
13
+
14
+ after do
15
+ @db.execute 'drop table datetime_test'
11
16
  end
12
17
 
13
18
  it 'should parse timestamps and do conversion accordingly' do
@@ -25,14 +30,19 @@ describe 'Adapter' do
25
30
  assert_timestamp_like time, fetch_timestamp_at(time), 'DST off'
26
31
  end
27
32
 
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
33
+ it 'should store fractional seconds' do
34
+ time = Time.now
35
+ datetime = time.to_datetime
36
+
37
+ @db.execute 'insert into datetime_test(ts) values (?), (?)', time, datetime
38
+ values = @db.execute('select ts from datetime_test').map(&:values).flatten
39
+
40
+ assert_equal 2, values.size
41
+
42
+ # postgres resolution is microsecond.
43
+ values.each do |value|
44
+ assert_equal datetime.strftime('%F %T %z'), value.strftime('%F %T %z')
45
+ assert_equal datetime.second_fraction.to_f.round(6), value.second_fraction.to_f.round(6)
36
46
  end
37
47
  end
38
48
 
@@ -49,8 +59,8 @@ describe 'Adapter' do
49
59
 
50
60
  def assert_timestamp_like expect, given, comment
51
61
  match = Regexp.new expect.to_time.strftime('%F %T')
52
- assert_kind_of Time, given
53
- assert_match match, given.strftime('%F %T'), comment
62
+ assert_kind_of DateTime, given
63
+ assert_match match, given.to_time.strftime('%F %T'), comment
54
64
  end
55
65
  end
56
66
  end
data/test/test_types.rb CHANGED
@@ -37,10 +37,10 @@ describe 'Adapter' do
37
37
  assert_kind_of TrueClass, result[:hacker]
38
38
  assert_kind_of FalseClass, result[:slacker]
39
39
  assert_kind_of Date, result[:created]
40
- assert_kind_of Time, result[:updated]
40
+ assert_kind_of DateTime, result[:updated]
41
41
 
42
42
  assert_equal dt, result[:updated].strftime('%F %T')
43
- assert_equal 65000, result[:updated].usec unless @db.kind_of?(Swift::DB::Mysql)
43
+ assert_equal 65000, result[:updated].to_time.usec unless @db.kind_of?(Swift::DB::Mysql)
44
44
  end
45
45
  end
46
46
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swift
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-16 00:00:00.000000000Z
13
+ date: 2012-03-21 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: minitest
17
- requirement: &6952860 !ruby/object:Gem::Requirement
17
+ requirement: &10639060 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,18 +22,7 @@ dependencies:
22
22
  version: 1.7.0
23
23
  type: :development
24
24
  prerelease: false
25
- version_requirements: *6952860
26
- - !ruby/object:Gem::Dependency
27
- name: eventmachine
28
- requirement: &6951140 !ruby/object:Gem::Requirement
29
- none: false
30
- requirements:
31
- - - ! '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: *6951140
25
+ version_requirements: *10639060
37
26
  description: A rational rudimentary database abstraction.
38
27
  email:
39
28
  - shane.hanna@gmail.com
@@ -43,11 +32,11 @@ extensions:
43
32
  - ext/extconf.rb
44
33
  extra_rdoc_files:
45
34
  - LICENSE
46
- - README.rdoc
35
+ - README.md
47
36
  files:
48
37
  - API.rdoc
49
38
  - LICENSE
50
- - README.rdoc
39
+ - README.md
51
40
  - Rakefile
52
41
  - VERSION
53
42
  - ext/adapter.cc
@@ -56,13 +45,11 @@ files:
56
45
  - ext/adapter_io.h
57
46
  - ext/attribute.cc
58
47
  - ext/attribute.h
48
+ - ext/datetime.cc
49
+ - ext/datetime.h
59
50
  - ext/extconf.rb
60
- - ext/pool.cc
61
- - ext/pool.h
62
51
  - ext/query.cc
63
52
  - ext/query.h
64
- - ext/request.cc
65
- - ext/request.h
66
53
  - ext/result.cc
67
54
  - ext/result.h
68
55
  - ext/statement.cc
@@ -77,7 +64,6 @@ files:
77
64
  - lib/swift/header.rb
78
65
  - lib/swift/identity_map.rb
79
66
  - lib/swift/migrations.rb
80
- - lib/swift/pool.rb
81
67
  - lib/swift/scheme.rb
82
68
  - lib/swift/type.rb
83
69
  - lib/swift/validations.rb
@@ -86,11 +72,12 @@ files:
86
72
  - test/house-explode.jpg
87
73
  - test/minitest_teardown_hack.rb
88
74
  - test/test_adapter.rb
75
+ - test/test_async.rb
76
+ - test/test_datetime_parser.rb
89
77
  - test/test_encoding.rb
90
78
  - test/test_error.rb
91
79
  - test/test_identity_map.rb
92
80
  - test/test_io.rb
93
- - test/test_pool.rb
94
81
  - test/test_scheme.rb
95
82
  - test/test_swift.rb
96
83
  - test/test_timestamps.rb
data/ext/pool.cc DELETED
@@ -1,96 +0,0 @@
1
- #include "pool.h"
2
-
3
- VALUE cSwiftPool;
4
-
5
- static void pool_free(dbi::ConnectionPool *self) {
6
- if (self) delete self;
7
- }
8
-
9
- VALUE pool_alloc(VALUE klass) {
10
- dbi::ConnectionPool *pool = 0;
11
- return Data_Wrap_Struct(klass, 0, pool_free, pool);
12
- }
13
-
14
- static dbi::ConnectionPool* pool_handle(VALUE self) {
15
- dbi::ConnectionPool *pool;
16
- Data_Get_Struct(self, dbi::ConnectionPool, pool);
17
- if (!pool) rb_raise(eSwiftRuntimeError, "Invalid object, did you forget to call #super ?");
18
- return pool;
19
- }
20
-
21
- VALUE pool_init(VALUE self, VALUE n, VALUE options) {
22
- VALUE db = rb_hash_aref(options, ID2SYM(rb_intern("db")));
23
- VALUE user = rb_hash_aref(options, ID2SYM(rb_intern("user")));
24
- VALUE driver = rb_hash_aref(options, ID2SYM(rb_intern("driver")));
25
-
26
- if (NIL_P(db)) rb_raise(eSwiftArgumentError, "Pool#new called without :db");
27
- if (NIL_P(driver)) rb_raise(eSwiftArgumentError, "#new called without :driver");
28
-
29
- user = NIL_P(user) ? current_user() : user;
30
- if (NUM2INT(n) < 1) rb_raise(eSwiftArgumentError, "Pool#new called with invalid pool size.");
31
-
32
- try {
33
- DATA_PTR(self) = new dbi::ConnectionPool(
34
- NUM2INT(n),
35
- CSTRING(driver),
36
- CSTRING(user),
37
- CSTRING(rb_hash_aref(options, ID2SYM(rb_intern("password")))),
38
- CSTRING(db),
39
- CSTRING(rb_hash_aref(options, ID2SYM(rb_intern("host")))),
40
- CSTRING(rb_hash_aref(options, ID2SYM(rb_intern("port"))))
41
- );
42
-
43
- rb_iv_set(self, "@timezone", rb_hash_aref(options, ID2SYM(rb_intern("timezone"))));
44
- }
45
- CATCH_DBI_EXCEPTIONS();
46
-
47
- return Qnil;
48
- }
49
-
50
- void pool_callback(dbi::AbstractResult *result) {
51
- VALUE callback = (VALUE)result->context;
52
-
53
- // NOTE: C Result object will be deallocated in dbic++
54
- if (!NIL_P(callback)) {
55
- VALUE obj = result_wrap_handle(cSwiftResult, 0, result, false);
56
- rb_iv_set(obj, "@timezone", rb_iv_get(callback, "@timezone"));
57
- rb_proc_call(callback, rb_ary_new3(1, obj));
58
- }
59
- }
60
-
61
- VALUE pool_execute(int argc, VALUE *argv, VALUE self) {
62
- int n;
63
- VALUE sql;
64
- VALUE bind_values;
65
- VALUE callback;
66
- VALUE request = Qnil;
67
-
68
- dbi::ConnectionPool *pool = pool_handle(self);
69
- rb_scan_args(argc, argv, "1*&", &sql, &bind_values, &callback);
70
-
71
- // The only way to pass timezone to the C callback routine.
72
- if (NIL_P(callback))
73
- rb_raise(eSwiftArgumentError, "No block given in Pool#execute");
74
- else
75
- rb_iv_set(callback, "@timezone", rb_iv_get(self, "@timezone"));
76
-
77
- try {
78
- Query query;
79
- query_bind_values(&query, bind_values);
80
- request = request_alloc(cSwiftRequest);
81
- DATA_PTR(request) = pool->execute(CSTRING(sql), query.bind, pool_callback, (void*)callback);
82
- return request;
83
- }
84
- CATCH_DBI_EXCEPTIONS();
85
- }
86
-
87
- void init_swift_pool() {
88
- VALUE mSwift = rb_define_module("Swift");
89
- VALUE mDB = rb_define_module_under(mSwift, "DB");
90
- cSwiftPool = rb_define_class_under(mDB, "Pool", rb_cObject);
91
-
92
- rb_define_alloc_func(cSwiftPool, pool_alloc);
93
-
94
- rb_define_method(cSwiftPool, "initialize", RUBY_METHOD_FUNC(pool_init), 2);
95
- rb_define_method(cSwiftPool, "execute", RUBY_METHOD_FUNC(pool_execute), -1);
96
- }
data/ext/pool.h DELETED
@@ -1,8 +0,0 @@
1
- #ifndef SWIFT_POOL_H
2
- #define SWIFT_POOL_H
3
-
4
- #include "swift.h"
5
-
6
- void init_swift_pool();
7
-
8
- #endif
data/ext/request.cc DELETED
@@ -1,44 +0,0 @@
1
- #include "request.h"
2
-
3
- VALUE cSwiftRequest;
4
-
5
- static void request_free(dbi::Request *request) {
6
- if(request) delete request;
7
- }
8
-
9
- VALUE request_alloc(VALUE klass) {
10
- dbi::Request *request = 0;
11
- return Data_Wrap_Struct(klass, 0, request_free, request);
12
- }
13
-
14
- static dbi::Request* request_handle(VALUE self) {
15
- dbi::Request *request;
16
- Data_Get_Struct(self, dbi::Request, request);
17
- if (!request) rb_raise(eSwiftRuntimeError, "Invalid object, did you forget to call #super ?");
18
- return request;
19
- }
20
-
21
- VALUE request_socket(VALUE self) {
22
- dbi::Request *request = request_handle(self);
23
- try {
24
- return INT2NUM(request->socket());
25
- }
26
- CATCH_DBI_EXCEPTIONS();
27
- }
28
-
29
- VALUE request_process(VALUE self) {
30
- dbi::Request *request = request_handle(self);
31
- try {
32
- return request->process() ? Qtrue : Qfalse;
33
- }
34
- CATCH_DBI_EXCEPTIONS();
35
- }
36
-
37
- void init_swift_request() {
38
- VALUE mSwift = rb_define_module("Swift");
39
- cSwiftRequest = rb_define_class_under(mSwift, "Request", rb_cObject);
40
-
41
- rb_define_alloc_func(cSwiftRequest, request_alloc);
42
- rb_define_method(cSwiftRequest, "socket", RUBY_METHOD_FUNC(request_socket), 0);
43
- rb_define_method(cSwiftRequest, "process", RUBY_METHOD_FUNC(request_process), 0);
44
- }
data/ext/request.h DELETED
@@ -1,10 +0,0 @@
1
- #ifndef SWIFT_REQUEST_H
2
- #define SWIFT_REQUEST_H
3
-
4
- #include "swift.h"
5
-
6
- extern VALUE cSwiftRequest;
7
- VALUE request_alloc(VALUE klass);
8
- void init_swift_request();
9
-
10
- #endif
data/lib/swift/pool.rb DELETED
@@ -1,76 +0,0 @@
1
- require 'eventmachine'
2
-
3
- module Swift
4
- class Pool
5
- module Handler
6
- def initialize request, pool
7
- @request, @pool = request, pool
8
- end
9
-
10
- def socket
11
- @request.socket
12
- end
13
-
14
- def notify_readable
15
- if @request.process
16
- detach
17
- @pool.detach self
18
- end
19
- end
20
-
21
- def notify_writable
22
- notify_readable
23
- end
24
- end # Handler
25
-
26
-
27
- def initialize size, options
28
- @pool = Swift::DB::Pool.new size, options
29
-
30
- # used to be used for db2
31
- @writable = false
32
- @pending = {}
33
- @queue = []
34
- end
35
-
36
- def attach c
37
- @pending[c] = true
38
- end
39
-
40
- def detach c
41
- @pending.delete(c)
42
- unless @queue.empty?
43
- sql, bind, callback = @queue.shift
44
- execute(sql, *bind, &callback)
45
- end
46
- end
47
-
48
- def attached? fd
49
- @pending.keys.select{|c| c.socket == fd}.length > 0
50
- end
51
-
52
- def execute sql, *bind, &callback
53
- request = @pool.execute sql, *bind, &callback
54
- # NOTE EM segfaults if we try to attach same fd twice.
55
- if request && !attached?(request.socket)
56
- EM.watch(request.socket, Handler, request, self) do |c|
57
- attach c
58
- c.notify_writable = @writable
59
- c.notify_readable = true
60
- end
61
- else
62
- @queue << [ sql, bind, callback ]
63
- end
64
- end
65
-
66
- def run &block
67
- EM.run{ yield self }
68
- end
69
- end # Pool
70
-
71
- def self.pool size, name = :default, &block
72
- pool = Pool.new(size, Swift.db(name).options)
73
- pool.run(&block) if block_given?
74
- pool
75
- end
76
- end # Swift
data/test/test_pool.rb DELETED
@@ -1,38 +0,0 @@
1
- require_relative 'helper'
2
- require 'swift/pool'
3
-
4
- describe 'Adapter' do
5
- supported_by Swift::DB::Postgres, Swift::DB::Mysql do
6
- describe 'Asynchronous connection pool' do
7
- before do
8
- Swift.db do |db|
9
- db.execute %q{drop table if exists users}
10
- db.execute %Q{create table users(name varchar(64))}
11
- end
12
- end
13
-
14
- it 'creates connection pool and runs queries' do
15
- rows = []
16
- Swift.pool(5) do |pool|
17
- assert pool
18
- assert Swift.db.write('users', %w{name}, StringIO.new("user1\nuser2\nuser3\n"))
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 }
24
- end
25
- end
26
- pool.execute('select * from users') do |rs|
27
- rows += rs.to_a
28
- end
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] }
35
- end
36
- end
37
- end
38
- end