swift 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/query.cc CHANGED
@@ -1,7 +1,9 @@
1
1
  #include "query.h"
2
+ #include <math.h>
2
3
 
3
- ID fstrftime, fto_s, fusec;
4
- VALUE dtformat, tzformat, utf8;
4
+ ID fstrftime;
5
+ VALUE dtformat, utf8;
6
+ VALUE cDateTime;
5
7
 
6
8
  VALUE query_execute(Query *query) {
7
9
  try {
@@ -11,10 +13,24 @@ VALUE query_execute(Query *query) {
11
13
  : query->handle->conn()->execute(query->sql, query->bind)
12
14
  );
13
15
  }
16
+ catch (dbi::ConnectionError &e) {
17
+ query->error_klass = eSwiftConnectionError;
18
+ snprintf(query->error_message, 8192, "%s", e.what());
19
+ }
14
20
  catch (dbi::Error &e) {
15
- snprintf(query->error, 8192, "%s", e.what());
16
- return Qfalse;
21
+ query->error_klass = eSwiftRuntimeError;
22
+ snprintf(query->error_message, 8192, "%s", e.what());
23
+ }
24
+ catch (std::bad_alloc &e) {
25
+ query->error_klass = rb_eNoMemError;
26
+ snprintf(query->error_message, 8192, "%s", e.what());
17
27
  }
28
+ catch (std::exception &e) {
29
+ query->error_klass = rb_eRuntimeError;
30
+ snprintf(query->error_message, 8192, "%s", e.what());
31
+ }
32
+
33
+ return Qfalse;
18
34
  }
19
35
 
20
36
  VALUE query_execute_statement(Query *query) {
@@ -25,10 +41,24 @@ VALUE query_execute_statement(Query *query) {
25
41
  : query->statement->execute(query->bind)
26
42
  );
27
43
  }
44
+ catch (dbi::ConnectionError &e) {
45
+ query->error_klass = eSwiftConnectionError;
46
+ snprintf(query->error_message, 8192, "%s", e.what());
47
+ }
28
48
  catch (dbi::Error &e) {
29
- snprintf(query->error, 8192, "%s", e.what());
30
- return Qfalse;
49
+ query->error_klass = eSwiftRuntimeError;
50
+ snprintf(query->error_message, 8192, "%s", e.what());
51
+ }
52
+ catch (std::bad_alloc &e) {
53
+ query->error_klass = rb_eNoMemError;
54
+ snprintf(query->error_message, 8192, "%s", e.what());
55
+ }
56
+ catch (std::exception &e) {
57
+ query->error_klass = rb_eRuntimeError;
58
+ snprintf(query->error_message, 8192, "%s", e.what());
31
59
  }
60
+
61
+ return Qfalse;
32
62
  }
33
63
 
34
64
  void query_bind_values(Query *query, VALUE bind_values) {
@@ -48,13 +78,8 @@ void query_bind_values(Query *query, VALUE bind_values) {
48
78
  bind_value = rb_funcall(bind_value, rb_intern("read"), 0);
49
79
  query->bind.push_back(dbi::PARAM_BINARY((unsigned char*)RSTRING_PTR(bind_value), RSTRING_LEN(bind_value)));
50
80
  }
51
- // TODO convert timestamps to server timezone if @timezone is set in adapter.
52
- else if (rb_obj_is_kind_of(bind_value, rb_cTime)) {
81
+ else if (rb_obj_is_kind_of(bind_value, rb_cTime) || rb_obj_is_kind_of(bind_value, cDateTime)) {
53
82
  std::string timestamp = RSTRING_PTR(rb_funcall(bind_value, fstrftime, 1, dtformat));
54
-
55
- timestamp += RSTRING_PTR(rb_funcall(rb_funcall(bind_value, fusec, 0), fto_s, 0));
56
- timestamp += RSTRING_PTR(rb_funcall(bind_value, fstrftime, 1, tzformat));
57
-
58
83
  query->bind.push_back(dbi::PARAM(timestamp));
59
84
  }
60
85
  else {
@@ -67,14 +92,13 @@ void query_bind_values(Query *query, VALUE bind_values) {
67
92
  }
68
93
 
69
94
  void init_swift_query() {
70
- fstrftime = rb_intern("strftime");
71
- fto_s = rb_intern("to_s");
72
- fusec = rb_intern("usec");
73
- dtformat = rb_str_new2("%F %T.");
74
- tzformat = rb_str_new2("%z");
95
+ rb_require("date");
96
+
75
97
  utf8 = rb_str_new2("UTF-8");
98
+ fstrftime = rb_intern("strftime");
99
+ dtformat = rb_str_new2("%F %T.%N %z");
100
+ cDateTime = CONST_GET(rb_mKernel, "DateTime");
76
101
 
77
102
  rb_global_variable(&utf8);
78
- rb_global_variable(&tzformat);
79
103
  rb_global_variable(&dtformat);
80
104
  }
data/ext/query.h CHANGED
@@ -8,7 +8,8 @@ struct Query {
8
8
  dbi::Handle *handle;
9
9
  dbi::AbstractStatement *statement;
10
10
  std::vector<dbi::Param> bind;
11
- char error[8192];
11
+ char error_message[8192];
12
+ VALUE error_klass;
12
13
  };
13
14
 
14
15
  VALUE query_execute(Query*);
data/ext/result.cc CHANGED
@@ -1,11 +1,11 @@
1
1
  #include "result.h"
2
+ #include "datetime.h"
2
3
  #include <math.h>
3
4
 
4
- VALUE cBigDecimal;
5
- VALUE cStringIO;
6
- VALUE cSwiftResult;
5
+ #define date_parse(klass, data,len) rb_funcall(datetime_parse(klass, data, len), fto_date, 0)
7
6
 
8
- ID fnew, fto_date, fload;
7
+ VALUE cBigDecimal, cStringIO, cSwiftResult;
8
+ ID fnew, fload, fto_date;
9
9
 
10
10
  void result_mark(ResultWrapper *handle) {
11
11
  if (handle)
@@ -57,13 +57,10 @@ static VALUE result_dup(VALUE self) {
57
57
 
58
58
  VALUE result_each(VALUE self) {
59
59
  uint64_t length;
60
- const char *data, *tzstring;
60
+ const char *data;
61
61
 
62
62
  dbi::AbstractResult *result = result_handle(self);
63
63
  VALUE scheme = rb_iv_get(self, "@scheme");
64
- VALUE timezone = rb_iv_get(self, "@timezone");
65
-
66
- tzstring = NIL_P(timezone) ? 0 : CSTRING(timezone);
67
64
 
68
65
  try {
69
66
  std::vector<string> result_fields = result->fields();
@@ -81,7 +78,7 @@ VALUE result_each(VALUE self) {
81
78
  rb_hash_aset(
82
79
  tuple,
83
80
  fields[column],
84
- typecast_field(result_types[column], data, length, tzstring)
81
+ typecast_field(result_types[column], data, length)
85
82
  );
86
83
  }
87
84
  else {
@@ -96,134 +93,7 @@ VALUE result_each(VALUE self) {
96
93
  return Qnil;
97
94
  }
98
95
 
99
- // Calculates local offset at a given time, including dst.
100
- int64_t client_tzoffset(int64_t local, int isdst) {
101
- struct tm tm;
102
- gmtime_r((const time_t*)&local, &tm);
103
- // TODO: This won't work in Lord Howe Island, Australia which uses half hour shift.
104
- return (int64_t)(local + (isdst ? 3600 : 0) - mktime(&tm));
105
- }
106
-
107
- // Calculates server offset at a given time, including dst.
108
- int64_t server_tzoffset(struct tm* tm, const char *zone) {
109
- uint64_t local;
110
- int64_t offset;
111
- char buffer[512];
112
- char *old, saved[512];
113
- struct tm tm_copy;
114
-
115
- // save current zone setting.
116
- if ((old = getenv("TZ"))) {
117
- strncpy(saved, old, 512);
118
- saved[511] = 0;
119
- }
120
-
121
- // setup.
122
- snprintf(buffer, 512, ":%s", zone);
123
- setenv("TZ", buffer, 1);
124
- tzset();
125
-
126
- // pretend we're on server timezone and calculate offset.
127
- memcpy(&tm_copy, tm, sizeof(struct tm));
128
- tm_copy.tm_isdst = -1;
129
- local = mktime(&tm_copy);
130
- offset = client_tzoffset(local, tm_copy.tm_isdst);
131
-
132
- // reset timezone to what it was before.
133
- old ? setenv("TZ", saved, 1) : unsetenv("TZ");
134
- tzset();
135
-
136
- return offset;
137
- }
138
-
139
- VALUE typecast_timestamp(const char *data, uint64_t len, const char *zone) {
140
- struct tm tm;
141
- uint64_t usec = 0;
142
- int64_t epoch, adjust, offset;
143
- char tzsign = 0, subsec[32];
144
- int tzhour = 0, tzmin = 0, lastmatch = -1;
145
-
146
- memset(&tm, 0, sizeof(struct tm));
147
- sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%n",
148
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &lastmatch);
149
-
150
- // parse millisecs if any
151
- if (lastmatch > 0 && lastmatch < len && *(data+lastmatch) == '.') {
152
- lastmatch++;
153
- int idx = 0;
154
- const char *ptr = data + lastmatch;
155
- while (*ptr && *ptr >= '0' && *ptr <= '9' && idx < 31) {
156
- subsec[idx++] = *ptr;
157
- ptr++;
158
- lastmatch++;
159
- }
160
- subsec[idx] = 0;
161
- usec = round(atoll(subsec) * (1000000 / pow(10, idx)));
162
- }
163
-
164
- tm.tm_year -= 1900;
165
- tm.tm_mon -= 1;
166
- tm.tm_isdst = -1;
167
- if (tm.tm_mday > 0) {
168
- epoch = mktime(&tm);
169
- adjust = client_tzoffset(epoch, tm.tm_isdst);
170
- offset = adjust;
171
-
172
- // parse timezone offsets if any - matches +HH:MM +HH MM +HHMM
173
- if (lastmatch > 0 && lastmatch < len) {
174
- const char *ptr = data + lastmatch;
175
- while(*ptr && *ptr != '+' && *ptr != '-') ptr++;
176
- tzsign = *ptr++;
177
- if (*ptr && *ptr >= '0' && *ptr <= '9') {
178
- tzhour = *ptr++ - '0';
179
- if (*ptr && *ptr >= '0' && *ptr <= '9') tzhour = tzhour*10 + *ptr++ - '0';
180
- while(*ptr && (*ptr < '0' || *ptr > '9')) ptr++;
181
- if (*ptr && *ptr >= '0' && *ptr <= '9') {
182
- tzmin = *ptr++ - '0';
183
- if (*ptr && *ptr >= '0' && *ptr <= '9') tzmin = tzmin*10 + *ptr++ - '0';
184
- }
185
- }
186
- }
187
-
188
- if (tzsign) {
189
- offset = tzsign == '+'
190
- ? (time_t)tzhour * 3600 + (time_t)tzmin * 60
191
- : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
192
- }
193
- else if (zone) {
194
- if (strncasecmp(zone, "UTC", 3) == 0 || strncasecmp(zone, "GMT", 3) == 0)
195
- offset = 0;
196
- else if (strcmp(zone, "+00:00") == 0 || strcmp(zone, "+0000") == 0)
197
- offset = 0;
198
- else if (sscanf(zone, "%c%02d%02d", &tzsign, &tzhour, &tzmin) == 3)
199
- offset = tzsign == '+'
200
- ? (time_t)tzhour * 3600 + (time_t)tzmin * 60
201
- : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
202
- else if (sscanf(zone, "%c%02d:%02d", &tzsign, &tzhour, &tzmin) >= 2)
203
- offset = tzsign == '+'
204
- ? (time_t)tzhour * 3600 + (time_t)tzmin * 60
205
- : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
206
- else
207
- offset = server_tzoffset(&tm, zone);
208
- }
209
-
210
- return rb_time_new(epoch+adjust-offset, usec);
211
- }
212
-
213
- printf("WARNING: Unable to parse timestamp value '%s'\n", data);
214
- return rb_str_new(data, len);
215
- }
216
-
217
- #define typecast_date(data,len,tz) rb_funcall(typecast_timestamp(data,len,tz), fto_date, 0)
218
-
219
- /*
220
- This is my wish list below for rubycore - to be built into core ruby.
221
- 1. Time class represents time - time zone invariant
222
- 2. Date class represents a date - time zone invariant
223
- 3. DateTime class represents a timestamp with full zoneinfo support.
224
- */
225
-
226
- VALUE typecast_field(int type, const char *data, uint64_t length, const char* timezone) {
96
+ VALUE typecast_field(int type, const char *data, uint64_t length) {
227
97
  switch(type) {
228
98
  case DBI_TYPE_BOOLEAN:
229
99
  return (data && (data[0] =='t' || data[0] == '1')) ? Qtrue : Qfalse;
@@ -232,9 +102,9 @@ VALUE typecast_field(int type, const char *data, uint64_t length, const char* ti
232
102
  case DBI_TYPE_BLOB:
233
103
  return rb_funcall(cStringIO, fnew, 1, rb_str_new(data, length));
234
104
  case DBI_TYPE_TIMESTAMP:
235
- return typecast_timestamp(data, length, timezone);
105
+ return datetime_parse(cSwiftDateTime, data, length);
236
106
  case DBI_TYPE_DATE:
237
- return typecast_date(data, length, timezone);
107
+ return date_parse(cSwiftDateTime, data, length);
238
108
  case DBI_TYPE_NUMERIC:
239
109
  return rb_funcall(cBigDecimal, fnew, 1, rb_str_new2(data));
240
110
  case DBI_TYPE_FLOAT:
@@ -284,29 +154,76 @@ VALUE result_fields(VALUE self) {
284
154
  CATCH_DBI_EXCEPTIONS();
285
155
  }
286
156
 
157
+ VALUE result_field_types(VALUE self) {
158
+ dbi::AbstractResult *result = result_handle(self);
159
+ std::vector<int> result_types = result->types();
160
+
161
+ VALUE types = rb_ary_new();
162
+ for (std::vector<int>::iterator it = result_types.begin(); it != result_types.end(); it++) {
163
+ switch(*it) {
164
+ case DBI_TYPE_BOOLEAN:
165
+ rb_ary_push(types, rb_str_new2("boolean"));
166
+ break;
167
+ case DBI_TYPE_INT:
168
+ rb_ary_push(types, rb_str_new2("integer"));
169
+ break;
170
+ case DBI_TYPE_BLOB:
171
+ rb_ary_push(types, rb_str_new2("blob"));
172
+ break;
173
+ case DBI_TYPE_TIMESTAMP:
174
+ rb_ary_push(types, rb_str_new2("timestamp"));
175
+ break;
176
+ case DBI_TYPE_DATE:
177
+ rb_ary_push(types, rb_str_new2("date"));
178
+ break;
179
+ case DBI_TYPE_NUMERIC:
180
+ rb_ary_push(types, rb_str_new2("numeric"));
181
+ break;
182
+ case DBI_TYPE_FLOAT:
183
+ rb_ary_push(types, rb_str_new2("float"));
184
+ break;
185
+ case DBI_TYPE_TIME:
186
+ rb_ary_push(types, rb_str_new2("time"));
187
+ break;
188
+ default:
189
+ rb_ary_push(types, rb_str_new2("text"));
190
+ }
191
+ }
192
+
193
+ return types;
194
+ }
195
+
196
+ VALUE result_retrieve(VALUE self) {
197
+ dbi::AbstractResult *result = result_handle(self);
198
+ while (result->consumeResult());
199
+ result->prepareResult();
200
+ return true;
201
+ }
202
+
287
203
  void init_swift_result() {
288
204
  rb_require("bigdecimal");
289
205
  rb_require("stringio");
290
- rb_require("date");
291
206
 
292
207
  VALUE mSwift = rb_define_module("Swift");
293
208
  cSwiftResult = rb_define_class_under(mSwift, "Result", rb_cObject);
294
209
  cStringIO = CONST_GET(rb_mKernel, "StringIO");
295
210
  cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
296
211
 
297
- fnew = rb_intern("new");
298
212
  fto_date = rb_intern("to_date");
213
+ fnew = rb_intern("new");
299
214
  fload = rb_intern("load");
300
215
 
301
216
  rb_define_alloc_func(cSwiftResult, result_alloc);
302
217
  rb_include_module(cSwiftResult, CONST_GET(rb_mKernel, "Enumerable"));
303
218
 
304
- rb_define_method(cSwiftResult, "clone", RUBY_METHOD_FUNC(result_clone), 0);
305
- rb_define_method(cSwiftResult, "dup", RUBY_METHOD_FUNC(result_dup), 0);
306
- rb_define_method(cSwiftResult, "each", RUBY_METHOD_FUNC(result_each), 0);
307
- rb_define_method(cSwiftResult, "insert_id", RUBY_METHOD_FUNC(result_insert_id), 0);
308
- rb_define_method(cSwiftResult, "rows", RUBY_METHOD_FUNC(result_rows), 0);
309
- rb_define_method(cSwiftResult, "columns", RUBY_METHOD_FUNC(result_columns), 0);
310
- rb_define_method(cSwiftResult, "fields", RUBY_METHOD_FUNC(result_fields), 0);
219
+ rb_define_method(cSwiftResult, "retrieve", RUBY_METHOD_FUNC(result_retrieve), 0);
220
+ rb_define_method(cSwiftResult, "clone", RUBY_METHOD_FUNC(result_clone), 0);
221
+ rb_define_method(cSwiftResult, "dup", RUBY_METHOD_FUNC(result_dup), 0);
222
+ rb_define_method(cSwiftResult, "each", RUBY_METHOD_FUNC(result_each), 0);
223
+ rb_define_method(cSwiftResult, "insert_id", RUBY_METHOD_FUNC(result_insert_id), 0);
224
+ rb_define_method(cSwiftResult, "rows", RUBY_METHOD_FUNC(result_rows), 0);
225
+ rb_define_method(cSwiftResult, "columns", RUBY_METHOD_FUNC(result_columns), 0);
226
+ rb_define_method(cSwiftResult, "fields", RUBY_METHOD_FUNC(result_fields), 0);
227
+ rb_define_method(cSwiftResult, "field_types", RUBY_METHOD_FUNC(result_field_types), 0);
311
228
  }
312
229
 
data/ext/result.h CHANGED
@@ -22,6 +22,6 @@ dbi::AbstractResult* result_handle(VALUE);
22
22
 
23
23
  VALUE result_each(VALUE);
24
24
 
25
- VALUE typecast_field(int, const char*, uint64_t, const char*);
25
+ VALUE typecast_field(int, const char*, uint64_t);
26
26
 
27
27
  #endif
data/ext/statement.cc CHANGED
@@ -56,7 +56,7 @@ static VALUE statement_execute(int argc, VALUE *argv, VALUE self) {
56
56
  if (dbi::_trace) dbi::logMessage(dbi::_trace_fd, dbi::formatParams(statement->command(), query.bind));
57
57
 
58
58
  if (rb_thread_blocking_region(((VALUE (*)(void*))query_execute_statement), &query, RUBY_UBF_IO, 0) == Qfalse)
59
- rb_raise(eSwiftRuntimeError, "%s", query.error);
59
+ rb_raise(query.error_klass, "%s", query.error_message);
60
60
  }
61
61
  CATCH_DBI_EXCEPTIONS();
62
62
 
data/ext/swift.cc CHANGED
@@ -96,11 +96,10 @@ extern "C" {
96
96
 
97
97
  init_swift_adapter();
98
98
  init_swift_attribute();
99
- init_swift_pool();
100
- init_swift_request();
101
99
  init_swift_result();
102
100
  init_swift_statement();
103
101
  init_swift_query();
102
+ init_swift_datetime();
104
103
 
105
104
  rb_define_module_function(mSwift, "init", RUBY_METHOD_FUNC(swift_init), 1);
106
105
  rb_define_module_function(mSwift, "trace", RUBY_METHOD_FUNC(swift_trace), -1);
data/ext/swift.h CHANGED
@@ -28,6 +28,9 @@ extern VALUE eSwiftConnectionError;
28
28
  } \
29
29
  catch (std::bad_alloc &error) { \
30
30
  rb_raise(rb_eNoMemError, "%s", error.what()); \
31
+ } \
32
+ catch (std::exception &error) { \
33
+ rb_raise(rb_eRuntimeError, "%s", error.what()); \
31
34
  }
32
35
 
33
36
 
@@ -42,9 +45,8 @@ inline VALUE current_user() {
42
45
  #include "query.h"
43
46
  #include "result.h"
44
47
  #include "statement.h"
45
- #include "request.h"
46
- #include "pool.h"
47
48
  #include "attribute.h"
49
+ #include "datetime.h"
48
50
 
49
51
  #undef SIZET2NUM
50
52
  #ifdef HAVE_LONG_LONG
@@ -7,6 +7,15 @@ module Swift
7
7
  #
8
8
  # @abstract
9
9
  class Sql < Adapter
10
+ def tables
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def fields table
15
+ result = execute("select * from #{table} limit 0")
16
+ Hash[result.fields.map(&:to_sym).zip(result.field_types)]
17
+ end
18
+
10
19
  protected
11
20
  def returning?
12
21
  raise NotImplementedError
@@ -57,7 +66,8 @@ module Swift
57
66
  when Type::Integer then attribute.serial ? 'serial' : 'integer'
58
67
  when Type::Float then 'float'
59
68
  when Type::BigDecimal then 'numeric'
60
- when Type::Time then 'timestamp'
69
+ when Type::Time then 'timestamp' # deprecated
70
+ when Type::DateTime then 'timestamp'
61
71
  when Type::Date then 'date'
62
72
  when Type::Boolean then 'boolean'
63
73
  when Type::IO then 'blob'
data/lib/swift/db.rb CHANGED
@@ -20,6 +20,10 @@ module Swift
20
20
  else super
21
21
  end
22
22
  end
23
+
24
+ def tables
25
+ execute("show tables").map(&:values).flatten
26
+ end
23
27
  end # Mysql
24
28
 
25
29
  class Sqlite3 < Adapter::Sql
@@ -47,13 +51,18 @@ module Swift
47
51
  when Type::Integer then attribute.serial ? 'integer primary key' : 'integer'
48
52
  when Type::Float then 'float'
49
53
  when Type::BigDecimal then 'numeric'
50
- when Type::Time then 'timestamp'
54
+ when Type::Time then 'timestamp' # deprecated
55
+ when Type::DateTime then 'timestamp'
51
56
  when Type::Date then 'date'
52
57
  when Type::Boolean then 'boolean'
53
58
  when Type::IO then 'blob'
54
59
  else 'text'
55
60
  end
56
61
  end
62
+
63
+ def tables
64
+ execute('select name from sqlite_master where type = ?', 'table').map(&:values).flatten
65
+ end
57
66
  end # Sqlite3
58
67
 
59
68
  class Postgres < Adapter::Sql
@@ -71,6 +80,10 @@ module Swift
71
80
  else super
72
81
  end
73
82
  end
83
+
84
+ def tables
85
+ execute('select tablename from pg_tables where schemaname = current_schema').map(&:values).flatten
86
+ end
74
87
  end # Postgres
75
88
  end # DB
76
89
  end # Swift
data/lib/swift/type.rb CHANGED
@@ -3,11 +3,18 @@ module Swift
3
3
  class BigDecimal < Attribute; end
4
4
  class Boolean < Attribute; end
5
5
  class Date < Attribute; end
6
- class Time < Attribute; end
6
+ class DateTime < Attribute; end
7
7
  class Float < Attribute; end
8
8
  class Integer < Attribute; end
9
9
  class IO < Attribute; end
10
10
  class String < Attribute; end
11
+
12
+ # deprecated
13
+ class Time < Attribute
14
+ def initialize *args
15
+ warn "Swift::Type::Time is deprecated. Use Swift::Type::DateTime instead"
16
+ super
17
+ end
18
+ end
11
19
  end # Type
12
20
  end # Swift
13
-
data/lib/swift.rb CHANGED
@@ -1,3 +1,12 @@
1
+ # try to require home_run in older rubies
2
+ unless %r{^1\.9\.[3-9]|^2\.}.match(RUBY_VERSION)
3
+ begin
4
+ require 'home_run'
5
+ rescue LoadError => e
6
+ warn "WARNING: DateTime parsing will be slow without home_run gem on Rubies older than 1.9.3"
7
+ end
8
+ end
9
+
1
10
  # Extension.
2
11
  require_relative '../ext/swift'
3
12
  require_relative 'swift/adapter'
@@ -66,7 +75,6 @@ module Swift
66
75
  # @option options [String] :password ('')
67
76
  # @option options [String] :host ('localhost')
68
77
  # @option options [Integer] :port (DB default)
69
- # @option options [String] :timezone (*nix TZ format) See http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
70
78
  # @return [Swift::Adapter]
71
79
  #
72
80
  # @see Swift::DB
data/swift.gemspec CHANGED
@@ -5,22 +5,22 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{swift}
8
- s.version = "0.13.0"
8
+ s.version = "0.14.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = [%q{Shane Hanna}, %q{Bharanee 'Barney' Rathna}]
12
- s.date = %q{2011-11-16}
12
+ s.date = %q{2012-03-21}
13
13
  s.description = %q{A rational rudimentary database abstraction.}
14
14
  s.email = [%q{shane.hanna@gmail.com}, %q{deepfryed@gmail.com}]
15
15
  s.extensions = [%q{ext/extconf.rb}]
16
16
  s.extra_rdoc_files = [
17
17
  "LICENSE",
18
- "README.rdoc"
18
+ "README.md"
19
19
  ]
20
20
  s.files = [
21
21
  "API.rdoc",
22
22
  "LICENSE",
23
- "README.rdoc",
23
+ "README.md",
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "ext/adapter.cc",
@@ -29,13 +29,11 @@ Gem::Specification.new do |s|
29
29
  "ext/adapter_io.h",
30
30
  "ext/attribute.cc",
31
31
  "ext/attribute.h",
32
+ "ext/datetime.cc",
33
+ "ext/datetime.h",
32
34
  "ext/extconf.rb",
33
- "ext/pool.cc",
34
- "ext/pool.h",
35
35
  "ext/query.cc",
36
36
  "ext/query.h",
37
- "ext/request.cc",
38
- "ext/request.h",
39
37
  "ext/result.cc",
40
38
  "ext/result.h",
41
39
  "ext/statement.cc",
@@ -50,7 +48,6 @@ Gem::Specification.new do |s|
50
48
  "lib/swift/header.rb",
51
49
  "lib/swift/identity_map.rb",
52
50
  "lib/swift/migrations.rb",
53
- "lib/swift/pool.rb",
54
51
  "lib/swift/scheme.rb",
55
52
  "lib/swift/type.rb",
56
53
  "lib/swift/validations.rb",
@@ -59,11 +56,12 @@ Gem::Specification.new do |s|
59
56
  "test/house-explode.jpg",
60
57
  "test/minitest_teardown_hack.rb",
61
58
  "test/test_adapter.rb",
59
+ "test/test_async.rb",
60
+ "test/test_datetime_parser.rb",
62
61
  "test/test_encoding.rb",
63
62
  "test/test_error.rb",
64
63
  "test/test_identity_map.rb",
65
64
  "test/test_io.rb",
66
- "test/test_pool.rb",
67
65
  "test/test_scheme.rb",
68
66
  "test/test_swift.rb",
69
67
  "test/test_timestamps.rb",
@@ -81,14 +79,11 @@ Gem::Specification.new do |s|
81
79
 
82
80
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
83
81
  s.add_development_dependency(%q<minitest>, [">= 1.7.0"])
84
- s.add_development_dependency(%q<eventmachine>, [">= 0"])
85
82
  else
86
83
  s.add_dependency(%q<minitest>, [">= 1.7.0"])
87
- s.add_dependency(%q<eventmachine>, [">= 0"])
88
84
  end
89
85
  else
90
86
  s.add_dependency(%q<minitest>, [">= 1.7.0"])
91
- s.add_dependency(%q<eventmachine>, [">= 0"])
92
87
  end
93
88
  end
94
89
 
data/test/test_adapter.rb CHANGED
@@ -26,6 +26,12 @@ describe 'Adapter' do
26
26
  Swift.trace false
27
27
  end
28
28
 
29
+ it 'records closed state' do
30
+ assert !Swift.db.closed?
31
+ Swift.db.close
32
+ assert Swift.db.closed?
33
+ end
34
+
29
35
  describe 'execute' do
30
36
  it 'executes without bind values' do
31
37
  assert @db.execute %q{select count(*) from users}
@@ -114,10 +120,18 @@ describe 'Adapter' do
114
120
  end
115
121
  end
116
122
 
123
+ describe 'schema information' do
124
+ it 'should list tables' do
125
+ assert_equal %w(users), @db.tables
126
+ end
127
+
128
+ it 'should list fields in a table with types' do
129
+ expect = {id: 'integer', name: 'text', email: 'text', created_at: 'timestamp'}
130
+ assert_equal expect, @db.fields('users')
131
+ end
132
+ end
133
+
117
134
 
118
- #--
119
- # TODO: Not sure how I feel about the block in write; feels like it's just there to get around the fields in the
120
- # argument list. How about write('users', %w{name, email, balance}, data)?
121
135
  describe 'bulk writes!' do
122
136
  it 'writes from an IO object' do
123
137
  data = StringIO.new "Sally Arthurton\tsally@local\nJonas Arthurton\tjonas@local\n"
@@ -130,7 +144,7 @@ describe 'Adapter' do
130
144
  end
131
145
 
132
146
  it 'writes with no columns specified' do
133
- ts = DateTime.parse('2010-01-01 00:00:00').to_time
147
+ ts = DateTime.parse('2010-01-01 00:00:00')
134
148
  data = "1\tSally Arthurton\tsally@local\t#{ts}\n"
135
149
  row = {id: 1, name: 'Sally Arthurton', email: 'sally@local', created_at: ts}
136
150