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